Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions crates/kilt-dip-support/src/did.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

// If you feel like getting in touch with us, you can do so at info@botlabs.org

//! Module to deal with cross-chain KILT DIDs.

use did::{
did_details::{DidPublicKey, DidPublicKeyDetails, DidVerificationKey},
DidSignature, DidVerificationKeyRelationship,
Expand All @@ -31,15 +33,24 @@ use crate::{
traits::{Bump, DidSignatureVerifierContext, DipCallOriginFilter},
};

/// Type returned by the Merkle proof verifier component of the DIP consumer
/// after verifying a DIP Merkle proof.
#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)]
pub(crate) struct RevealedDidKeysAndSignature<RevealedDidKeys, BlockNumber> {
/// The keys revelaed in the Merkle proof.
pub merkle_leaves: RevealedDidKeys,
/// The [`DIDSignature`] + consumer chain block number to which the DID
/// signature is anchored.
pub did_signature: TimeBoundDidSignature<BlockNumber>,
}

/// A DID signature anchored to a specific block height.
#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)]
pub struct TimeBoundDidSignature<BlockNumber> {
/// The signature.
pub signature: DidSignature,
/// The block number, in the context of the local executor, to which the
/// signature is anchored.
pub block_number: BlockNumber,
}

Expand Down Expand Up @@ -75,6 +86,30 @@ impl From<RevealedDidKeysSignatureAndCallVerifierError> for u8 {
}
}

/// Proof verifier that tries to verify a DID signature over a given payload by
/// using one of the DID keys revealed in the Merkle proof. This verifier is
/// typically used in conjunction with a verifier that takes a user-provided
/// input Merkle proof, verifies it, and transforms it into a struct that this
/// and other verifiers can easily consume, e.g., a list of DID keys.
/// The generic types are the following:
/// * `Call`: The call to be dispatched on the local chain after verifying the
/// DID signature.
/// * `Submitter`: The blockchain account (**not** the identity subject)
/// submitting the cross-chain transaction (and paying for its execution
/// fees).
/// * `DidLocalDetails`: Any information associated to the identity subject that
/// is stored locally, e.g., under the `IdentityEntries` map of the
/// `pallet-dip-consumer` pallet.
/// * `MerkleProofEntries`: The type returned by the Merkle proof verifier that
/// includes the identity parts revealed in the Merkle proof.
/// * `ContextProvider`: Provides additional local context (e.g., current block
/// number) to verify the DID signature.
/// * `RemoteKeyId`: Definition of a DID key ID as specified by the provider.
/// * `RemoteAccountId`: Definition of a linked account ID as specified by the
/// provider.
/// * `RemoteBlockNumber`: Definition of a block number on the provider chain.
/// * `CallVerifier`: A type specifying whether the provided `Call` can be
/// dispatched with the information provided in the DIP proof.
pub(crate) struct RevealedDidKeysSignatureAndCallVerifier<
Call,
Submitter,
Expand Down Expand Up @@ -135,7 +170,6 @@ impl<
DipCallOriginFilter<Call, OriginInfo = (DidVerificationKey<RemoteAccountId>, DidVerificationKeyRelationship)>,
{
#[cfg(not(feature = "runtime-benchmarks"))]
#[allow(clippy::result_unit_err)]
pub(crate) fn verify_did_signature_for_call(
call: &Call,
submitter: &Submitter,
Expand All @@ -147,7 +181,7 @@ impl<
> {
use frame_support::ensure;

let block_number = ContextProvider::block_number();
let block_number = ContextProvider::current_block_number();
let is_signature_fresh = if let Some(blocks_ago_from_now) =
block_number.checked_sub(&merkle_revealed_did_signature.did_signature.block_number)
{
Expand Down Expand Up @@ -213,7 +247,7 @@ impl<
> {
use sp_core::ed25519;

let block_number = ContextProvider::block_number();
let block_number = ContextProvider::current_block_number();
// Computed but ignored
if let Some(blocks_ago_from_now) =
block_number.checked_sub(&merkle_revealed_did_signature.did_signature.block_number)
Expand Down
152 changes: 140 additions & 12 deletions crates/kilt-dip-support/src/export/child.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@ use crate::{
merkle::{DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves},
state_proofs::{parachain::DipIdentityCommitmentProofVerifierError, relay_chain::ParachainHeadProofVerifierError},
traits::{
Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, ProviderParachainStateInfo,
Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, ProviderParachainStorageInfo,
RelayChainStorageInfo,
},
utils::OutputOf,
BoundedBlindedValue, FrameSystemDidSignatureContext, ProviderParachainStateInfoViaProviderPallet,
};

/// A KILT-specific DIP identity proof for a parent consumer that supports
/// versioning.
///
/// For more info, refer to the version-specific proofs.
#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)]
#[non_exhaustive]
pub enum VersionedChildParachainDipStateProof<
Expand Down Expand Up @@ -118,8 +122,48 @@ where
}
}

// Implements the same `IdentityProvider` trait, but it is internally configured
// by receiving the runtime definitions of both the provider and the receiver.
/// Proof verifier configured given a specific KILT runtime implementation.
///
/// A specialization of the
/// [`GenericVersionedDipChildProviderStateProofVerifier`] type, with
/// configurations derived from the provided KILT runtime.
///
/// The generic types are the following:
/// * `KiltRuntime`: A KILT runtime definition.
/// * `KiltParachainId`: The ID of the specific KILT parachain instance.
/// * `RelayChainInfo`: The type providing information about the consumer
/// (relay)chain.
/// * `KiltDipMerkleHasher`: The hashing algorithm used by the KILT parachain
/// for the generation of the DIP identity commitment.
/// * `LocalDidCallVerifier`: Logic to map `RuntimeCall`s to a specific DID key
/// relationship. This information is used once the Merkle proof is verified,
/// to filter only the revealed keys that match the provided relationship.
/// * `MAX_REVEALED_KEYS_COUNT`: Max number of DID keys that the verifier will
/// accept revealed as part of the DIP identity proof.
/// * `MAX_REVEALED_ACCOUNTS_COUNT`: Max number of linked accounts that the
/// verifier will accept revealed as part of the DIP identity proof.
/// * `MAX_DID_SIGNATURE_DURATION`: Max number of blocks a cross-chain DID
/// signature is considered fresh.
///
/// It specializes the [`GenericVersionedDipChildProviderStateProofVerifier`]
/// type by using the following types for its generics:
/// * `RelayChainInfo`: The provided `RelayChainInfo`.
/// * `ChildProviderParachainId`: The provided `KiltParachainId`.
/// * `ChildProviderStateInfo`: The
/// [`ProviderParachainStateInfoViaProviderPallet`] type configured with the
/// provided `KiltRuntime`.
/// * `ProviderDipMerkleHasher`: The provided `KiltDipMerkleHasher`.
/// * `ProviderDidKeyId`: The [`KeyIdOf`] type configured with the provided
/// `KiltRuntime`.
/// * `ProviderAccountId`: The `KiltRuntime::AccountId` type.
/// * `ProviderWeb3Name`: The `KiltRuntime::Web3Name` type.
/// * `ProviderLinkedAccountId`: The [`LinkableAccountId`] type.
/// * `MAX_REVEALED_KEYS_COUNT`: The provided `MAX_REVEALED_KEYS_COUNT`.
/// * `MAX_REVEALED_ACCOUNTS_COUNT`: The provided `MAX_REVEALED_ACCOUNTS_COUNT`.
/// * `LocalContextProvider`: The [`FrameSystemDidSignatureContext`] type
/// configured with the provided `KiltRuntime` and
/// `MAX_DID_SIGNATURE_DURATION`.
/// * `LocalDidCallVerifier`: The provided `LocalDidCallVerifier`.
pub struct KiltVersionedChildProviderVerifier<
KiltRuntime,
KiltParachainId,
Expand Down Expand Up @@ -258,10 +302,15 @@ impl<
}
}

// More generic version compared to `VersionedChildKiltProviderVerifier`, to be
// used in cases in which it is not possible or not desirable to depend on the
// whole provider runtime definition. Hence, required types must be filled in
// manually.
/// Generic proof verifier for KILT-specific DIP identity proofs of different
/// versions coming from a child provider running one of the available KILT
/// runtimes.
///
/// It expects the DIP proof to be a [`VersionedChildParachainDipStateProof`],
/// and returns [`RevealedDidMerkleProofLeaves`] if the proof is successfully
/// verified.
///
/// For more info, refer to the version-specific proof identifiers.
pub struct GenericVersionedDipChildProviderStateProofVerifier<
RelayChainInfo,
ChildProviderParachainId,
Expand Down Expand Up @@ -346,8 +395,10 @@ impl<

ChildProviderParachainId: Get<RelayChainInfo::ParaId>,

ChildProviderStateInfo:
ProviderParachainStateInfo<Identifier = ConsumerRuntime::Identifier, Commitment = ProviderDipMerkleHasher::Out>,
ChildProviderStateInfo: ProviderParachainStorageInfo<
Identifier = ConsumerRuntime::Identifier,
Commitment = ProviderDipMerkleHasher::Out,
>,
OutputOf<ChildProviderStateInfo::Hasher>: Ord + From<OutputOf<<RelayChainInfo as RelayChainStorageInfo>::Hasher>>,
ChildProviderStateInfo::BlockNumber: Parameter + 'static,
ChildProviderStateInfo::Commitment: Decode,
Expand Down Expand Up @@ -431,7 +482,7 @@ pub mod latest {
pub use super::v0::ChildParachainDipStateProof;
}

mod v0 {
pub mod v0 {
use super::*;

use parity_scale_codec::Codec;
Expand All @@ -457,24 +508,101 @@ mod v0 {
},
traits::{
Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry,
ProviderParachainStateInfo, RelayChainStorageInfo,
ProviderParachainStorageInfo, RelayChainStorageInfo,
},
utils::OutputOf,
};

/// The expected format of a cross-chain DIP identity proof when the
/// identity information is bridged from a provider that is a child of
/// the chain where the information is consumed (i.e., consumer
/// chain).
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
pub struct ChildParachainDipStateProof<
ParentBlockHeight: Copy + Into<U256> + TryFrom<U256>,
ParentBlockHasher: Hash,
DipMerkleProofBlindedValues,
DipMerkleProofRevealedLeaf,
> {
/// The state proof for the given parachain head.
para_state_root: ParachainRootStateProof<ParentBlockHeight>,
/// The relaychain header for the relaychain block specified in the
/// `para_state_root`.
relay_header: Header<ParentBlockHeight, ParentBlockHasher>,
/// The raw state proof for the DIP commitment of the given subject.
dip_identity_commitment: Vec<Vec<u8>>,
/// The cross-chain DID signature.
did: DipMerkleProofAndDidSignature<DipMerkleProofBlindedValues, DipMerkleProofRevealedLeaf, ParentBlockHeight>,
}

/// Generic proof verifier for KILT-specific DIP identity proofs coming from
/// a child provider running one of the available KILT runtimes.
/// The proof verification step is performed on every request, and this
/// specific verifier has no knowledge of caching or storing state about the
/// subject. It only takes the provided
/// `ConsumerRuntime::LocalIdentityInfo` and increases it if the proof is
/// successfully verified, to prevent replay attacks. If additional logic is
/// to be stored under the `ConsumerRuntime::LocalIdentityInfo` entry, a
/// different verifier or a wrapper around this verifier must be built.
///
/// It expects the DIP proof to be a
/// [`VersionedChildParachainDipStateProof`], and returns
/// [`RevealedDidMerkleProofLeaves`] if the proof is successfully verified.
/// This information is then made availabe as an origin to the downstream
/// call dispatched.
///
/// The verifier performs the following steps:
/// 1. Verifies the state proof about the state root of the relaychain block
/// at the provided height. The state root is retrieved from the provided
/// relaychain header, which is checked to be the header of a
/// previously-finalized relaychain block.
/// 2. Verifies the state proof about the DIP commitment value on the
/// provider parachain at the block finalized at the given relaychain
/// block, using the relay state root validated in the previous step.
/// 3. Verifies the DIP Merkle proof revealing parts of the subject's DID
/// Document against the retrieved DIP commitment validated in the
/// previous step.
/// 4. Verifies the cross-chain DID signature over the payload composed by
/// the SCALE-encoded tuple of `(C, D, S, B, G, E)`, with:
/// * `C`: The `RuntimeCall` to dispatch after performing DIP
/// verification.
/// * `D`: The local details associated to the DID subject as stored in
/// the [`pallet_dip_consumer`] `IdentityEntries` storage map.
/// * `S`: The tx submitter's address.
/// * `B`: The block number of the consumer chain provided in the
/// cross-chain DID signature.
/// * `G`: The genesis hash of the consumer chain.
/// * `E`: Any additional information provided by the
/// `LocalContextProvider` implementation.
/// The generic types
/// indicate the following:
/// * `RelayChainInfo`: The type providing information about the consumer
/// (relay)chain.
/// * `ChildProviderParachainId`: The parachain ID of the provider KILT
/// child parachain.
/// * `ChildProviderStateInfo`: The type providing storage and state
/// information about the provider KILT child parachain.
/// * `ProviderDipMerkleHasher`: The hashing algorithm used by the KILT
/// parachain for the generation of the DIP identity commitment.
/// * `ProviderDidKeyId`: The runtime type of a DID key ID as defined by the
/// KILT child parachain.
/// * `ProviderAccountId`: The runtime type of an account ID as defined by
/// the KILT child parachain.
/// * `ProviderWeb3Name`: The runtime type of a web3name as defined by the
/// KILT child parachain.
/// * `ProviderLinkedAccountId`: The runtime type of a linked account ID as
/// defined by the KILT child parachain.
/// * `MAX_REVEALED_KEYS_COUNT`: Max number of DID keys that the verifier
/// will accept revealed as part of the DIP identity proof.
/// * `MAX_REVEALED_ACCOUNTS_COUNT`: Max number of linked accounts that the
/// verifier will accept revealed as part of the DIP identity proof.
/// * `LocalContextProvider`: The type providing context of the consumer
/// chain (e.g., current block number) for the sake of cross-chain DID
/// signature verification.
/// * `LocalDidCallVerifier`: Logic to map `RuntimeCall`s to a specific DID
/// key relationship. This information is used once the Merkle proof is
/// verified, to filter only the revealed keys that match the provided
/// relationship.
pub struct DipChildProviderStateProofVerifier<
RelayChainInfo,
ChildProviderParachainId,
Expand Down Expand Up @@ -559,7 +687,7 @@ mod v0 {

ChildProviderParachainId: Get<RelayChainInfo::ParaId>,

ChildProviderStateInfo: ProviderParachainStateInfo<
ChildProviderStateInfo: ProviderParachainStorageInfo<
Identifier = ConsumerRuntime::Identifier,
Commitment = ProviderDipMerkleHasher::Out,
>,
Expand Down
5 changes: 5 additions & 0 deletions crates/kilt-dip-support/src/export/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ pub mod v0 {

#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)]
pub struct ParachainRootStateProof<RelayBlockHeight> {
/// The relaychain block height for which the proof has been generated.
pub(crate) relay_block_height: RelayBlockHeight,
/// The raw state proof.
pub(crate) proof: BoundedBlindedValue<u8>,
}

Expand All @@ -49,7 +51,10 @@ pub mod v0 {

#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)]
pub struct DipMerkleProofAndDidSignature<BlindedValues, Leaf, BlockNumber> {
/// The DIP Merkle proof revealing some leaves about the DID subject's
/// identity.
pub(crate) leaves: DidMerkleProof<BlindedValues, Leaf>,
/// The cross-chain DID signature.
pub(crate) signature: TimeBoundDidSignature<BlockNumber>,
}

Expand Down
2 changes: 2 additions & 0 deletions crates/kilt-dip-support/src/export/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

// If you feel like getting in touch with us, you can do so at info@botlabs.org

/// Verification logic to integrate a child chain as a DIP provider.
pub mod child;
/// Verification logic to integrate a sibling chain as a DIP provider.
pub mod sibling;

mod common;
Expand Down
Loading