diff --git a/Cargo.lock b/Cargo.lock index a5aef17c56..8915054d6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6491,6 +6491,7 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", + "sp-io", "sp-std", ] diff --git a/crates/kilt-dip-support/src/export/child.rs b/crates/kilt-dip-support/src/export/child.rs new file mode 100644 index 0000000000..c238080099 --- /dev/null +++ b/crates/kilt-dip-support/src/export/child.rs @@ -0,0 +1,553 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship}; +use pallet_dip_consumer::traits::IdentityProofVerifier; +use parity_scale_codec::{Codec, Decode, Encode, HasCompact}; +use scale_info::TypeInfo; +use sp_core::{RuntimeDebug, U256}; +use sp_runtime::traits::{AtLeast32BitUnsigned, CheckedSub, Get, Hash, MaybeDisplay, Member, SimpleBitOps}; +use sp_std::{marker::PhantomData, vec::Vec}; + +use crate::{ + did::RevealedDidKeysSignatureAndCallVerifierError, + merkle::{DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, + state_proofs::{parachain::DipIdentityCommitmentProofVerifierError, relay_chain::ParachainHeadProofVerifierError}, + traits::{ + Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, ProviderParachainStateInfo, + RelayChainStorageInfo, + }, + utils::OutputOf, +}; + +#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] +#[non_exhaustive] +pub enum VersionedChildParachainDipStateProof< + ParentBlockHeight: Copy + Into + TryFrom, + ParentBlockHasher: Hash, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, +> { + V0( + v0::ChildParachainDipStateProof< + ParentBlockHeight, + ParentBlockHasher, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + >, + ), +} + +pub enum DipChildProviderStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, +> { + UnsupportedVersion, + InvalidBlockHeight, + InvalidBlockHash, + ParachainHeadMerkleProof(ParachainHeadMerkleProofVerificationError), + IdentityCommitmentMerkleProof(IdentityCommitmentMerkleProofVerificationError), + DipProof(DipProofVerificationError), + DidSignature(DidSignatureVerificationError), +} + +impl< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + > + From< + DipChildProviderStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + >, + > for u16 +where + ParachainHeadMerkleProofVerificationError: Into, + IdentityCommitmentMerkleProofVerificationError: Into, + DipProofVerificationError: Into, + DidSignatureVerificationError: Into, +{ + fn from( + value: DipChildProviderStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + >, + ) -> Self { + match value { + DipChildProviderStateProofVerifierError::UnsupportedVersion => 0, + DipChildProviderStateProofVerifierError::InvalidBlockHeight => 1, + DipChildProviderStateProofVerifierError::InvalidBlockHash => 2, + DipChildProviderStateProofVerifierError::ParachainHeadMerkleProof(error) => { + u8::MAX as u16 + error.into() as u16 + } + DipChildProviderStateProofVerifierError::IdentityCommitmentMerkleProof(error) => { + u8::MAX as u16 * 2 + error.into() as u16 + } + DipChildProviderStateProofVerifierError::DipProof(error) => u8::MAX as u16 * 3 + error.into() as u16, + DipChildProviderStateProofVerifierError::DidSignature(error) => u8::MAX as u16 * 4 + error.into() as u16, + } + } +} + +pub struct VersionedDipChildProviderStateProofVerifier< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, +>( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + )>, +); + +impl< + Call, + Subject, + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for VersionedDipChildProviderStateProofVerifier< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > where + Call: Encode, + TxSubmitter: Encode, + + RelayChainInfo: RelayChainStorageInfo + + HistoricalBlockRegistry< + BlockNumber = ::BlockNumber, + Hasher = ::Hasher, + >, + OutputOf<::Hasher>: + Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, + ::BlockNumber: Copy + + Into + + TryFrom + + HasCompact + + Member + + sp_std::hash::Hash + + MaybeDisplay + + AtLeast32BitUnsigned + + Codec, + RelayChainInfo::Key: AsRef<[u8]>, + + ChildProviderParachainId: Get, + + ChildProviderStateInfo: ProviderParachainStateInfo, + OutputOf: Ord + From::Hasher>>, + ChildProviderStateInfo::BlockNumber: Encode + Clone, + ChildProviderStateInfo::Commitment: Decode, + ChildProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: + DidSignatureVerifierContext::BlockNumber>, + LocalContextProvider::BlockNumber: CheckedSub + From, + LocalContextProvider::Hash: Encode, + LocalContextProvider::SignedExtra: Encode, + LocalDidDetails: Bump + Default + Encode, + LocalDidCallVerifier: + DipCallOriginFilter, DidVerificationKeyRelationship)>, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Encode + Clone + Into, + ProviderAccountId: Encode + Clone, + ProviderLinkedAccountId: Encode + Clone, + ProviderWeb3Name: Encode + Clone, +{ + type Error = DipChildProviderStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type IdentityDetails = LocalDidDetails; + type Proof = VersionedChildParachainDipStateProof< + ::BlockNumber, + ::Hasher, + Vec>, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + ProviderAccountId, + ChildProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + >; + type Submitter = TxSubmitter; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + ChildProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + match proof { + VersionedChildParachainDipStateProof::V0(v0_proof) => { + v0::DipChildProviderStateProofVerifier::< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + >::verify_proof_for_call_against_details(call, subject, submitter, identity_details, v0_proof) + } + } + } +} + +pub mod latest { + pub use super::v0::ChildParachainDipStateProof; +} + +mod v0 { + use super::*; + + use parity_scale_codec::Codec; + use sp_runtime::{ + generic::Header, + traits::{AtLeast32BitUnsigned, Hash, MaybeDisplay, Member, SimpleBitOps}, + }; + use sp_std::{borrow::Borrow, vec::Vec}; + + use crate::{ + did::{ + RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, + RevealedDidKeysSignatureAndCallVerifierError, + }, + export::common::v0::{DipMerkleProofAndDidSignature, ParachainRootStateProof}, + merkle::{ + DidMerkleProofVerifier, DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, + RevealedDidMerkleProofLeaves, + }, + state_proofs::{ + parachain::{DipIdentityCommitmentProofVerifier, DipIdentityCommitmentProofVerifierError}, + relay_chain::{ParachainHeadProofVerifier, ParachainHeadProofVerifierError}, + }, + traits::{ + Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, + ProviderParachainStateInfo, RelayChainStorageInfo, + }, + utils::OutputOf, + }; + + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] + pub struct ChildParachainDipStateProof< + ParentBlockHeight: Copy + Into + TryFrom, + ParentBlockHasher: Hash, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + > { + para_state_root: ParachainRootStateProof, + relay_header: Header, + dip_identity_commitment: Vec>, + did: DipMerkleProofAndDidSignature, + } + + pub struct DipChildProviderStateProofVerifier< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + >( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + )>, + ); + + impl< + Call, + Subject, + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for DipChildProviderStateProofVerifier< + RelayChainInfo, + ChildProviderParachainId, + ChildProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > where + Call: Encode, + TxSubmitter: Encode, + + RelayChainInfo: RelayChainStorageInfo + + HistoricalBlockRegistry< + BlockNumber = ::BlockNumber, + Hasher = ::Hasher, + >, + OutputOf<::Hasher>: + Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, + ::BlockNumber: Copy + + Into + + TryFrom + + HasCompact + + Member + + sp_std::hash::Hash + + MaybeDisplay + + AtLeast32BitUnsigned + + Codec, + RelayChainInfo::Key: AsRef<[u8]>, + + ChildProviderParachainId: Get, + + ChildProviderStateInfo: + ProviderParachainStateInfo, + OutputOf: + Ord + From::Hasher>>, + ChildProviderStateInfo::BlockNumber: Encode + Clone, + ChildProviderStateInfo::Commitment: Decode, + ChildProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: + DidSignatureVerifierContext::BlockNumber>, + LocalContextProvider::BlockNumber: CheckedSub + From, + LocalContextProvider::Hash: Encode, + LocalContextProvider::SignedExtra: Encode, + LocalDidDetails: Bump + Default + Encode, + LocalDidCallVerifier: DipCallOriginFilter< + Call, + OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship), + >, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Encode + Clone + Into, + ProviderAccountId: Encode + Clone, + ProviderLinkedAccountId: Encode + Clone, + ProviderWeb3Name: Encode + Clone, + { + type Error = DipChildProviderStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type IdentityDetails = LocalDidDetails; + type Proof = ChildParachainDipStateProof< + ::BlockNumber, + ::Hasher, + Vec>, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + ProviderAccountId, + ChildProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + >; + type Submitter = TxSubmitter; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + ChildProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + // 1. Retrieve block hash from provider at the proof height + let block_hash_at_height = RelayChainInfo::block_hash_for(&proof.para_state_root.relay_block_height) + .ok_or(DipChildProviderStateProofVerifierError::InvalidBlockHeight)?; + + // 1.1 Verify that the provided header hashes to the same block has retrieved + if block_hash_at_height != proof.relay_header.hash() { + return Err(DipChildProviderStateProofVerifierError::InvalidBlockHash); + } + // 1.2 If so, extract the state root from the header + let state_root_at_height = proof.relay_header.state_root; + + // FIXME: Compilation error + // 2. Verify relay chain proof + let provider_parachain_header = + ParachainHeadProofVerifier::::verify_proof_for_parachain_with_root( + &ChildProviderParachainId::get(), + &state_root_at_height, + proof.para_state_root.proof, + ) + .map_err(DipChildProviderStateProofVerifierError::ParachainHeadMerkleProof)?; + + // 3. Verify parachain state proof. + let subject_identity_commitment = + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( + subject, + provider_parachain_header.state_root.into(), + proof.dip_identity_commitment, + ) + .map_err(DipChildProviderStateProofVerifierError::IdentityCommitmentMerkleProof)?; + + // 4. Verify DIP merkle proof. + let proof_leaves = DidMerkleProofVerifier::< + ProviderDipMerkleHasher, + _, + _, + _, + _, + _, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >::verify_dip_merkle_proof(&subject_identity_commitment, proof.did.leaves) + .map_err(DipChildProviderStateProofVerifierError::DipProof)?; + + // 5. Verify DID signature. + RevealedDidKeysSignatureAndCallVerifier::< + _, + _, + _, + _, + LocalContextProvider, + _, + _, + _, + LocalDidCallVerifier, + >::verify_did_signature_for_call( + call, + submitter, + identity_details, + RevealedDidKeysAndSignature { + merkle_leaves: proof_leaves.borrow(), + did_signature: proof.did.signature, + }, + ) + .map_err(DipChildProviderStateProofVerifierError::DidSignature)?; + Ok(proof_leaves) + } + } +} diff --git a/crates/kilt-dip-support/src/export/common.rs b/crates/kilt-dip-support/src/export/common.rs new file mode 100644 index 0000000000..d0eff66d68 --- /dev/null +++ b/crates/kilt-dip-support/src/export/common.rs @@ -0,0 +1,42 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +pub mod latest { + pub use super::v0::{DipMerkleProofAndDidSignature, ParachainRootStateProof}; +} + +pub mod v0 { + use parity_scale_codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_core::RuntimeDebug; + use sp_std::vec::Vec; + + use crate::{did::TimeBoundDidSignature, merkle::DidMerkleProof}; + + #[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] + pub struct ParachainRootStateProof { + pub(crate) relay_block_height: RelayBlockHeight, + pub(crate) proof: Vec>, + } + + #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] + pub struct DipMerkleProofAndDidSignature { + pub(crate) leaves: DidMerkleProof, + pub(crate) signature: TimeBoundDidSignature, + } +} diff --git a/crates/kilt-dip-support/src/export/mod.rs b/crates/kilt-dip-support/src/export/mod.rs new file mode 100644 index 0000000000..c6a92e7d5b --- /dev/null +++ b/crates/kilt-dip-support/src/export/mod.rs @@ -0,0 +1,34 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +mod child; +mod common; +mod sibling; + +pub use child::{ + DipChildProviderStateProofVerifierError, VersionedChildParachainDipStateProof, + VersionedDipChildProviderStateProofVerifier, +}; +pub use sibling::{ + DipSiblingProviderStateProofVerifierError, VersionedDipSiblingProviderStateProofVerifier, + VersionedSiblingParachainDipStateProof, +}; + +pub mod latest { + pub use super::{child::latest::*, common::latest::*, sibling::latest::*}; +} diff --git a/crates/kilt-dip-support/src/export/sibling.rs b/crates/kilt-dip-support/src/export/sibling.rs new file mode 100644 index 0000000000..e0b3154c54 --- /dev/null +++ b/crates/kilt-dip-support/src/export/sibling.rs @@ -0,0 +1,497 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2023 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use did::{did_details::DidVerificationKey, DidVerificationKeyRelationship}; +use pallet_dip_consumer::traits::IdentityProofVerifier; +use parity_scale_codec::{Decode, Encode, HasCompact}; +use scale_info::TypeInfo; +use sp_core::{RuntimeDebug, U256}; +use sp_runtime::traits::{CheckedSub, Get}; +use sp_std::{marker::PhantomData, vec::Vec}; + +use crate::{ + did::RevealedDidKeysSignatureAndCallVerifierError, + merkle::{DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, RevealedDidMerkleProofLeaves}, + state_proofs::{parachain::DipIdentityCommitmentProofVerifierError, relay_chain::ParachainHeadProofVerifierError}, + traits::{self, Bump, DidSignatureVerifierContext, DipCallOriginFilter}, + utils::OutputOf, +}; + +#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] +#[non_exhaustive] +pub enum VersionedSiblingParachainDipStateProof< + RelayBlockHeight, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + LocalBlockNumber, +> { + V0( + v0::SiblingParachainDipStateProof< + RelayBlockHeight, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + LocalBlockNumber, + >, + ), +} + +pub enum DipSiblingProviderStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, +> { + UnsupportedVersion, + ParachainHeadMerkleProof(ParachainHeadMerkleProofVerificationError), + IdentityCommitmentMerkleProof(IdentityCommitmentMerkleProofVerificationError), + DipProof(DipProofVerificationError), + DidSignature(DidSignatureVerificationError), +} + +impl< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + > + From< + DipSiblingProviderStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + >, + > for u16 +where + ParachainHeadMerkleProofVerificationError: Into, + IdentityCommitmentMerkleProofVerificationError: Into, + DipProofVerificationError: Into, + DidSignatureVerificationError: Into, +{ + fn from( + value: DipSiblingProviderStateProofVerifierError< + ParachainHeadMerkleProofVerificationError, + IdentityCommitmentMerkleProofVerificationError, + DipProofVerificationError, + DidSignatureVerificationError, + >, + ) -> Self { + match value { + DipSiblingProviderStateProofVerifierError::UnsupportedVersion => 0, + DipSiblingProviderStateProofVerifierError::ParachainHeadMerkleProof(error) => { + u8::MAX as u16 + error.into() as u16 + } + DipSiblingProviderStateProofVerifierError::IdentityCommitmentMerkleProof(error) => { + u8::MAX as u16 * 2 + error.into() as u16 + } + DipSiblingProviderStateProofVerifierError::DipProof(error) => u8::MAX as u16 * 3 + error.into() as u16, + DipSiblingProviderStateProofVerifierError::DidSignature(error) => u8::MAX as u16 * 4 + error.into() as u16, + } + } +} + +pub struct VersionedDipSiblingProviderStateProofVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, +>( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + )>, +); + +impl< + Call, + Subject, + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for VersionedDipSiblingProviderStateProofVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > where + Call: Encode, + TxSubmitter: Encode, + + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, + OutputOf: Ord, + RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayChainStateInfo::Key: AsRef<[u8]>, + + SiblingProviderParachainId: Get, + + SiblingProviderStateInfo: + traits::ProviderParachainStateInfo, + OutputOf: Ord + From>, + SiblingProviderStateInfo::BlockNumber: Encode + Clone, + SiblingProviderStateInfo::Commitment: Decode, + SiblingProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: DidSignatureVerifierContext, + LocalContextProvider::BlockNumber: Encode + CheckedSub + From + PartialOrd, + LocalContextProvider::Hash: Encode, + LocalContextProvider::SignedExtra: Encode, + LocalDidDetails: Bump + Default + Encode, + LocalDidCallVerifier: + DipCallOriginFilter, DidVerificationKeyRelationship)>, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Encode + Clone + Into, + ProviderAccountId: Encode + Clone, + ProviderLinkedAccountId: Encode + Clone, + ProviderWeb3Name: Encode + Clone, +{ + type Error = DipSiblingProviderStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type IdentityDetails = LocalDidDetails; + type Proof = VersionedSiblingParachainDipStateProof< + RelayChainStateInfo::BlockNumber, + Vec>, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + ProviderAccountId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + LocalContextProvider::BlockNumber, + >; + type Submitter = TxSubmitter; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + match proof { + VersionedSiblingParachainDipStateProof::V0(v0_proof) => { + v0::DipSiblingProviderStateProofVerifier::< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + >::verify_proof_for_call_against_details(call, subject, submitter, identity_details, v0_proof) + } + } + } +} + +pub mod latest { + pub use super::v0::SiblingParachainDipStateProof; +} + +mod v0 { + use super::*; + + use sp_std::borrow::Borrow; + + use crate::{ + did::{RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier}, + export::common::v0::{DipMerkleProofAndDidSignature, ParachainRootStateProof}, + merkle::DidMerkleProofVerifier, + state_proofs::{parachain::DipIdentityCommitmentProofVerifier, relay_chain::ParachainHeadProofVerifier}, + traits::ProviderParachainStateInfo, + }; + + #[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] + pub struct SiblingParachainDipStateProof< + RelayBlockHeight, + DipMerkleProofBlindedValues, + DipMerkleProofRevealedLeaf, + LocalBlockNumber, + > { + para_state_root: ParachainRootStateProof, + dip_identity_commitment: Vec>, + did: DipMerkleProofAndDidSignature, + } + + #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] + pub struct DipSiblingProviderStateProofVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + >( + #[allow(clippy::type_complexity)] + PhantomData<( + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + )>, + ); + + impl< + Call, + Subject, + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + const MAX_REVEALED_KEYS_COUNT: u32, + const MAX_REVEALED_ACCOUNTS_COUNT: u32, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > IdentityProofVerifier + for DipSiblingProviderStateProofVerifier< + RelayChainStateInfo, + SiblingProviderParachainId, + SiblingProviderStateInfo, + TxSubmitter, + ProviderDipMerkleHasher, + ProviderDidKeyId, + ProviderAccountId, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + LocalDidDetails, + LocalContextProvider, + LocalDidCallVerifier, + > where + Call: Encode, + TxSubmitter: Encode, + + RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, + OutputOf: Ord, + RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, + RelayChainStateInfo::Key: AsRef<[u8]>, + + SiblingProviderParachainId: Get, + + SiblingProviderStateInfo: + traits::ProviderParachainStateInfo, + OutputOf: Ord + From>, + SiblingProviderStateInfo::BlockNumber: Encode + Clone, + SiblingProviderStateInfo::Commitment: Decode, + SiblingProviderStateInfo::Key: AsRef<[u8]>, + + LocalContextProvider: DidSignatureVerifierContext, + LocalContextProvider::BlockNumber: Encode + CheckedSub + From + PartialOrd, + LocalContextProvider::Hash: Encode, + LocalContextProvider::SignedExtra: Encode, + LocalDidDetails: Bump + Default + Encode, + LocalDidCallVerifier: DipCallOriginFilter< + Call, + OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship), + >, + + ProviderDipMerkleHasher: sp_core::Hasher, + ProviderDidKeyId: Encode + Clone + Into, + ProviderAccountId: Encode + Clone, + ProviderLinkedAccountId: Encode + Clone, + ProviderWeb3Name: Encode + Clone, + { + type Error = DipSiblingProviderStateProofVerifierError< + ParachainHeadProofVerifierError, + DipIdentityCommitmentProofVerifierError, + DidMerkleProofVerifierError, + RevealedDidKeysSignatureAndCallVerifierError, + >; + type IdentityDetails = LocalDidDetails; + type Proof = SiblingParachainDipStateProof< + RelayChainStateInfo::BlockNumber, + Vec>, + RevealedDidMerkleProofLeaf< + ProviderDidKeyId, + ProviderAccountId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + >, + LocalContextProvider::BlockNumber, + >; + type Submitter = TxSubmitter; + type VerificationResult = RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + SiblingProviderStateInfo::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >; + + fn verify_proof_for_call_against_details( + call: &Call, + subject: &Subject, + submitter: &Self::Submitter, + identity_details: &mut Option, + proof: Self::Proof, + ) -> Result { + // 1. Verify relay chain proof. + let provider_parachain_header = + ParachainHeadProofVerifier::::verify_proof_for_parachain( + &SiblingProviderParachainId::get(), + &proof.para_state_root.relay_block_height, + proof.para_state_root.proof, + ) + .map_err(DipSiblingProviderStateProofVerifierError::ParachainHeadMerkleProof)?; + + // 2. Verify parachain state proof. + let subject_identity_commitment = + DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( + subject, + provider_parachain_header.state_root.into(), + proof.dip_identity_commitment, + ) + .map_err(DipSiblingProviderStateProofVerifierError::IdentityCommitmentMerkleProof)?; + + // 3. Verify DIP merkle proof. + let proof_leaves: RevealedDidMerkleProofLeaves< + ProviderDidKeyId, + ProviderAccountId, + ::BlockNumber, + ProviderWeb3Name, + ProviderLinkedAccountId, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + > = DidMerkleProofVerifier::< + ProviderDipMerkleHasher, + _, + _, + _, + _, + _, + MAX_REVEALED_KEYS_COUNT, + MAX_REVEALED_ACCOUNTS_COUNT, + >::verify_dip_merkle_proof(&subject_identity_commitment, proof.did.leaves) + .map_err(DipSiblingProviderStateProofVerifierError::DipProof)?; + + // 4. Verify DID signature. + RevealedDidKeysSignatureAndCallVerifier::< + _, + _, + _, + _, + LocalContextProvider, + _, + _, + _, + LocalDidCallVerifier, + >::verify_did_signature_for_call( + call, + submitter, + identity_details, + RevealedDidKeysAndSignature { + merkle_leaves: proof_leaves.borrow(), + did_signature: proof.did.signature, + }, + ) + .map_err(DipSiblingProviderStateProofVerifierError::DidSignature)?; + + Ok(proof_leaves) + } + } +} diff --git a/crates/kilt-dip-support/src/lib.rs b/crates/kilt-dip-support/src/lib.rs index 0d0e80425e..2daacfc640 100644 --- a/crates/kilt-dip-support/src/lib.rs +++ b/crates/kilt-dip-support/src/lib.rs @@ -20,603 +20,13 @@ #![cfg_attr(not(feature = "std"), no_std)] -use parity_scale_codec::{Codec, Decode, Encode, HasCompact}; -use scale_info::TypeInfo; -use sp_core::{Get, RuntimeDebug, U256}; -use sp_runtime::{ - generic::Header, - traits::{AtLeast32BitUnsigned, CheckedSub, Hash, MaybeDisplay, Member, SimpleBitOps}, -}; -use sp_std::{borrow::Borrow, marker::PhantomData, vec::Vec}; - -use ::did::{did_details::DidVerificationKey, DidVerificationKeyRelationship}; -use pallet_dip_consumer::traits::IdentityProofVerifier; - -use crate::{ - did::{ - RevealedDidKeysAndSignature, RevealedDidKeysSignatureAndCallVerifier, - RevealedDidKeysSignatureAndCallVerifierError, TimeBoundDidSignature, - }, - merkle::{ - DidMerkleProof, DidMerkleProofVerifier, DidMerkleProofVerifierError, RevealedDidMerkleProofLeaf, - RevealedDidMerkleProofLeaves, - }, - state_proofs::{ - parachain::{DipIdentityCommitmentProofVerifier, DipIdentityCommitmentProofVerifierError}, - relay_chain::{ParachainHeadProofVerifier, ParachainHeadProofVerifierError}, - }, - traits::{ - Bump, DidSignatureVerifierContext, DipCallOriginFilter, HistoricalBlockRegistry, ProviderParachainStateInfo, - RelayChainStorageInfo, - }, - utils::OutputOf, -}; - pub mod did; pub mod merkle; pub mod state_proofs; pub mod traits; pub mod utils; -pub use state_proofs::relay_chain::RococoStateRootsViaRelayStorePallet; - -#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] -pub struct SiblingParachainDipStateProof< - RelayBlockHeight, - DipMerkleProofBlindedValues, - DipMerkleProofRevealedLeaf, - LocalBlockNumber, -> { - para_state_root: ParachainRootStateProof, - dip_identity_commitment: Vec>, - did: DipMerkleProofAndDidSignature, -} - -#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug, TypeInfo, Clone)] -pub struct ParachainRootStateProof { - relay_block_height: RelayBlockHeight, - proof: Vec>, -} - -#[derive(Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo, Clone)] -pub struct DipMerkleProofAndDidSignature { - leaves: DidMerkleProof, - signature: TimeBoundDidSignature, -} - -pub enum DipSiblingProviderStateProofVerifierError< - ParachainHeadMerkleProofVerificationError, - IdentityCommitmentMerkleProofVerificationError, - DipProofVerificationError, - DidSignatureVerificationError, -> { - ParachainHeadMerkleProofVerificationError(ParachainHeadMerkleProofVerificationError), - IdentityCommitmentMerkleProofVerificationError(IdentityCommitmentMerkleProofVerificationError), - DipProofVerificationError(DipProofVerificationError), - DidSignatureVerificationError(DidSignatureVerificationError), -} - -impl< - ParachainHeadMerkleProofVerificationError, - IdentityCommitmentMerkleProofVerificationError, - DipProofVerificationError, - DidSignatureVerificationError, - > - From< - DipSiblingProviderStateProofVerifierError< - ParachainHeadMerkleProofVerificationError, - IdentityCommitmentMerkleProofVerificationError, - DipProofVerificationError, - DidSignatureVerificationError, - >, - > for u16 -where - ParachainHeadMerkleProofVerificationError: Into, - IdentityCommitmentMerkleProofVerificationError: Into, - DipProofVerificationError: Into, - DidSignatureVerificationError: Into, -{ - fn from( - value: DipSiblingProviderStateProofVerifierError< - ParachainHeadMerkleProofVerificationError, - IdentityCommitmentMerkleProofVerificationError, - DipProofVerificationError, - DidSignatureVerificationError, - >, - ) -> Self { - match value { - DipSiblingProviderStateProofVerifierError::ParachainHeadMerkleProofVerificationError(error) => { - error.into() as u16 - } - DipSiblingProviderStateProofVerifierError::IdentityCommitmentMerkleProofVerificationError(error) => { - u8::MAX as u16 + error.into() as u16 - } - DipSiblingProviderStateProofVerifierError::DipProofVerificationError(error) => { - u8::MAX as u16 * 2 + error.into() as u16 - } - DipSiblingProviderStateProofVerifierError::DidSignatureVerificationError(error) => { - u8::MAX as u16 * 3 + error.into() as u16 - } - } - } -} - -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct DipSiblingProviderStateProofVerifier< - RelayChainStateInfo, - SiblingProviderParachainId, - SiblingProviderStateInfo, - TxSubmitter, - ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderAccountId, - ProviderWeb3Name, - ProviderLinkedAccountId, - const MAX_REVEALED_KEYS_COUNT: u32, - const MAX_REVEALED_ACCOUNTS_COUNT: u32, - LocalDidDetails, - LocalContextProvider, - LocalDidCallVerifier, ->( - #[allow(clippy::type_complexity)] - PhantomData<( - RelayChainStateInfo, - SiblingProviderParachainId, - SiblingProviderStateInfo, - TxSubmitter, - ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderAccountId, - ProviderWeb3Name, - ProviderLinkedAccountId, - LocalDidDetails, - LocalContextProvider, - LocalDidCallVerifier, - )>, -); - -impl< - Call, - Subject, - RelayChainStateInfo, - SiblingProviderParachainId, - SiblingProviderStateInfo, - TxSubmitter, - ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderAccountId, - ProviderWeb3Name, - ProviderLinkedAccountId, - const MAX_REVEALED_KEYS_COUNT: u32, - const MAX_REVEALED_ACCOUNTS_COUNT: u32, - LocalDidDetails, - LocalContextProvider, - LocalDidCallVerifier, - > IdentityProofVerifier - for DipSiblingProviderStateProofVerifier< - RelayChainStateInfo, - SiblingProviderParachainId, - SiblingProviderStateInfo, - TxSubmitter, - ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderAccountId, - ProviderWeb3Name, - ProviderLinkedAccountId, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - LocalDidDetails, - LocalContextProvider, - LocalDidCallVerifier, - > where - Call: Encode, - TxSubmitter: Encode, - - RelayChainStateInfo: traits::RelayChainStorageInfo + traits::RelayChainStateInfo, - OutputOf: Ord, - RelayChainStateInfo::BlockNumber: Copy + Into + TryFrom + HasCompact, - RelayChainStateInfo::Key: AsRef<[u8]>, - - SiblingProviderParachainId: Get, - - SiblingProviderStateInfo: - traits::ProviderParachainStateInfo, - OutputOf: Ord + From>, - SiblingProviderStateInfo::BlockNumber: Encode + Clone, - SiblingProviderStateInfo::Commitment: Decode, - SiblingProviderStateInfo::Key: AsRef<[u8]>, - - LocalContextProvider: DidSignatureVerifierContext, - LocalContextProvider::BlockNumber: Encode + CheckedSub + From + PartialOrd, - LocalContextProvider::Hash: Encode, - LocalContextProvider::SignedExtra: Encode, - LocalDidDetails: Bump + Default + Encode, - LocalDidCallVerifier: - DipCallOriginFilter, DidVerificationKeyRelationship)>, - - ProviderDipMerkleHasher: sp_core::Hasher, - ProviderDidKeyId: Encode + Clone + Into, - ProviderAccountId: Encode + Clone, - ProviderLinkedAccountId: Encode + Clone, - ProviderWeb3Name: Encode + Clone, -{ - type Error = DipSiblingProviderStateProofVerifierError< - ParachainHeadProofVerifierError, - DipIdentityCommitmentProofVerifierError, - DidMerkleProofVerifierError, - RevealedDidKeysSignatureAndCallVerifierError, - >; - type IdentityDetails = LocalDidDetails; - type Proof = SiblingParachainDipStateProof< - RelayChainStateInfo::BlockNumber, - Vec>, - RevealedDidMerkleProofLeaf< - ProviderDidKeyId, - ProviderAccountId, - SiblingProviderStateInfo::BlockNumber, - ProviderWeb3Name, - ProviderLinkedAccountId, - >, - LocalContextProvider::BlockNumber, - >; - type Submitter = TxSubmitter; - type VerificationResult = RevealedDidMerkleProofLeaves< - ProviderDidKeyId, - ProviderAccountId, - SiblingProviderStateInfo::BlockNumber, - ProviderWeb3Name, - ProviderLinkedAccountId, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - >; - - fn verify_proof_for_call_against_details( - call: &Call, - subject: &Subject, - submitter: &Self::Submitter, - identity_details: &mut Option, - proof: Self::Proof, - ) -> Result { - // 1. Verify relay chain proof. - let provider_parachain_header = ParachainHeadProofVerifier::::verify_proof_for_parachain( - &SiblingProviderParachainId::get(), - &proof.para_state_root.relay_block_height, - proof.para_state_root.proof, - ) - .map_err(DipSiblingProviderStateProofVerifierError::ParachainHeadMerkleProofVerificationError)?; - - // 2. Verify parachain state proof. - let subject_identity_commitment = - DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( - subject, - provider_parachain_header.state_root.into(), - proof.dip_identity_commitment, - ) - .map_err(DipSiblingProviderStateProofVerifierError::IdentityCommitmentMerkleProofVerificationError)?; - - // 3. Verify DIP merkle proof. - let proof_leaves = DidMerkleProofVerifier::< - ProviderDipMerkleHasher, - _, - _, - _, - _, - _, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - >::verify_dip_merkle_proof(&subject_identity_commitment, proof.did.leaves) - .map_err(DipSiblingProviderStateProofVerifierError::DipProofVerificationError)?; +mod export; - // 4. Verify DID signature. - RevealedDidKeysSignatureAndCallVerifier::< - _, - _, - _, - _, - LocalContextProvider, - _, - _, - _, - LocalDidCallVerifier, - >::verify_did_signature_for_call( - call, - submitter, - identity_details, - RevealedDidKeysAndSignature { - merkle_leaves: proof_leaves.borrow(), - did_signature: proof.did.signature, - }, - ).map_err(DipSiblingProviderStateProofVerifierError::DidSignatureVerificationError)?; - - Ok(proof_leaves) - } -} - -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct ChildParachainDipStateProof< - ParentBlockHeight: Copy + Into + TryFrom, - ParentBlockHasher: Hash, - DipMerkleProofBlindedValues, - DipMerkleProofRevealedLeaf, -> { - para_state_root: ParachainRootStateProof, - relay_header: Header, - dip_identity_commitment: Vec>, - did: DipMerkleProofAndDidSignature, -} - -pub enum DipChildProviderStateProofVerifierError< - ParachainHeadMerkleProofVerificationError, - IdentityCommitmentMerkleProofVerificationError, - DipProofVerificationError, - DidSignatureVerificationError, -> { - InvalidBlockHeight, - InvalidBlockHash, - ParachainHeadMerkleProofVerificationError(ParachainHeadMerkleProofVerificationError), - IdentityCommitmentMerkleProofVerificationError(IdentityCommitmentMerkleProofVerificationError), - DipProofVerificationError(DipProofVerificationError), - DidSignatureVerificationError(DidSignatureVerificationError), -} - -impl< - ParachainHeadMerkleProofVerificationError, - IdentityCommitmentMerkleProofVerificationError, - DipProofVerificationError, - DidSignatureVerificationError, - > - From< - DipChildProviderStateProofVerifierError< - ParachainHeadMerkleProofVerificationError, - IdentityCommitmentMerkleProofVerificationError, - DipProofVerificationError, - DidSignatureVerificationError, - >, - > for u16 -where - ParachainHeadMerkleProofVerificationError: Into, - IdentityCommitmentMerkleProofVerificationError: Into, - DipProofVerificationError: Into, - DidSignatureVerificationError: Into, -{ - fn from( - value: DipChildProviderStateProofVerifierError< - ParachainHeadMerkleProofVerificationError, - IdentityCommitmentMerkleProofVerificationError, - DipProofVerificationError, - DidSignatureVerificationError, - >, - ) -> Self { - match value { - DipChildProviderStateProofVerifierError::InvalidBlockHeight => 0, - DipChildProviderStateProofVerifierError::InvalidBlockHash => 1, - DipChildProviderStateProofVerifierError::ParachainHeadMerkleProofVerificationError(error) => { - u8::MAX as u16 + error.into() as u16 - } - DipChildProviderStateProofVerifierError::IdentityCommitmentMerkleProofVerificationError(error) => { - u8::MAX as u16 * 2 + error.into() as u16 - } - DipChildProviderStateProofVerifierError::DipProofVerificationError(error) => { - u8::MAX as u16 * 3 + error.into() as u16 - } - DipChildProviderStateProofVerifierError::DidSignatureVerificationError(error) => { - u8::MAX as u16 * 4 + error.into() as u16 - } - } - } -} - -pub struct DipChildProviderStateProofVerifier< - RelayChainInfo, - ChildProviderParachainId, - ChildProviderStateInfo, - TxSubmitter, - ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderAccountId, - ProviderWeb3Name, - ProviderLinkedAccountId, - const MAX_REVEALED_KEYS_COUNT: u32, - const MAX_REVEALED_ACCOUNTS_COUNT: u32, - LocalDidDetails, - LocalContextProvider, - LocalDidCallVerifier, ->( - #[allow(clippy::type_complexity)] - PhantomData<( - RelayChainInfo, - ChildProviderParachainId, - ChildProviderStateInfo, - TxSubmitter, - ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderAccountId, - ProviderWeb3Name, - ProviderLinkedAccountId, - LocalDidDetails, - LocalContextProvider, - LocalDidCallVerifier, - )>, -); - -impl< - Call, - Subject, - RelayChainInfo, - ChildProviderParachainId, - ChildProviderStateInfo, - TxSubmitter, - ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderAccountId, - ProviderWeb3Name, - ProviderLinkedAccountId, - const MAX_REVEALED_KEYS_COUNT: u32, - const MAX_REVEALED_ACCOUNTS_COUNT: u32, - LocalDidDetails, - LocalContextProvider, - LocalDidCallVerifier, - > IdentityProofVerifier - for DipChildProviderStateProofVerifier< - RelayChainInfo, - ChildProviderParachainId, - ChildProviderStateInfo, - TxSubmitter, - ProviderDipMerkleHasher, - ProviderDidKeyId, - ProviderAccountId, - ProviderWeb3Name, - ProviderLinkedAccountId, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - LocalDidDetails, - LocalContextProvider, - LocalDidCallVerifier, - > where - Call: Encode, - TxSubmitter: Encode, - - RelayChainInfo: RelayChainStorageInfo - + HistoricalBlockRegistry< - BlockNumber = ::BlockNumber, - Hasher = ::Hasher, - >, - OutputOf<::Hasher>: - Ord + Default + sp_std::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec, - ::BlockNumber: Copy - + Into - + TryFrom - + HasCompact - + Member - + sp_std::hash::Hash - + MaybeDisplay - + AtLeast32BitUnsigned - + Codec, - RelayChainInfo::Key: AsRef<[u8]>, - - ChildProviderParachainId: Get, - - ChildProviderStateInfo: ProviderParachainStateInfo, - OutputOf: Ord + From::Hasher>>, - ChildProviderStateInfo::BlockNumber: Encode + Clone, - ChildProviderStateInfo::Commitment: Decode, - ChildProviderStateInfo::Key: AsRef<[u8]>, - - LocalContextProvider: - DidSignatureVerifierContext::BlockNumber>, - LocalContextProvider::BlockNumber: CheckedSub + From, - LocalContextProvider::Hash: Encode, - LocalContextProvider::SignedExtra: Encode, - LocalDidDetails: Bump + Default + Encode, - LocalDidCallVerifier: - DipCallOriginFilter, DidVerificationKeyRelationship)>, - - ProviderDipMerkleHasher: sp_core::Hasher, - ProviderDidKeyId: Encode + Clone + Into, - ProviderAccountId: Encode + Clone, - ProviderLinkedAccountId: Encode + Clone, - ProviderWeb3Name: Encode + Clone, -{ - type Error = DipChildProviderStateProofVerifierError< - ParachainHeadProofVerifierError, - DipIdentityCommitmentProofVerifierError, - DidMerkleProofVerifierError, - RevealedDidKeysSignatureAndCallVerifierError, - >; - type IdentityDetails = LocalDidDetails; - type Proof = ChildParachainDipStateProof< - ::BlockNumber, - ::Hasher, - Vec>, - RevealedDidMerkleProofLeaf< - ProviderDidKeyId, - ProviderAccountId, - ChildProviderStateInfo::BlockNumber, - ProviderWeb3Name, - ProviderLinkedAccountId, - >, - >; - type Submitter = TxSubmitter; - type VerificationResult = RevealedDidMerkleProofLeaves< - ProviderDidKeyId, - ProviderAccountId, - ChildProviderStateInfo::BlockNumber, - ProviderWeb3Name, - ProviderLinkedAccountId, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - >; - - fn verify_proof_for_call_against_details( - call: &Call, - subject: &Subject, - submitter: &Self::Submitter, - identity_details: &mut Option, - proof: Self::Proof, - ) -> Result { - // 1. Retrieve block hash from provider at the proof height - let block_hash_at_height = RelayChainInfo::block_hash_for(&proof.para_state_root.relay_block_height) - .ok_or(DipChildProviderStateProofVerifierError::InvalidBlockHeight)?; - - // 1.1 Verify that the provided header hashes to the same block has retrieved - if block_hash_at_height != proof.relay_header.hash() { - return Err(DipChildProviderStateProofVerifierError::InvalidBlockHash); - } - // 1.2 If so, extract the state root from the header - let state_root_at_height = proof.relay_header.state_root; - - // FIXME: Compilation error - // 2. Verify relay chain proof - let provider_parachain_header = - ParachainHeadProofVerifier::::verify_proof_for_parachain_with_root( - &ChildProviderParachainId::get(), - &state_root_at_height, - proof.para_state_root.proof, - ) - .map_err(DipChildProviderStateProofVerifierError::ParachainHeadMerkleProofVerificationError)?; - - // 3. Verify parachain state proof. - let subject_identity_commitment = - DipIdentityCommitmentProofVerifier::::verify_proof_for_identifier( - subject, - provider_parachain_header.state_root.into(), - proof.dip_identity_commitment, - ) - .map_err(DipChildProviderStateProofVerifierError::IdentityCommitmentMerkleProofVerificationError)?; - - // 4. Verify DIP merkle proof. - let proof_leaves = DidMerkleProofVerifier::< - ProviderDipMerkleHasher, - _, - _, - _, - _, - _, - MAX_REVEALED_KEYS_COUNT, - MAX_REVEALED_ACCOUNTS_COUNT, - >::verify_dip_merkle_proof(&subject_identity_commitment, proof.did.leaves) - .map_err(DipChildProviderStateProofVerifierError::DipProofVerificationError)?; - - // 5. Verify DID signature. - RevealedDidKeysSignatureAndCallVerifier::< - _, - _, - _, - _, - LocalContextProvider, - _, - _, - _, - LocalDidCallVerifier, - >::verify_did_signature_for_call( - call, - submitter, - identity_details, - RevealedDidKeysAndSignature { - merkle_leaves: proof_leaves.borrow(), - did_signature: proof.did.signature, - }, - ).map_err(DipChildProviderStateProofVerifierError::DidSignatureVerificationError)?; - Ok(proof_leaves) - } -} +pub use export::*; +pub use state_proofs::relay_chain::RococoStateRootsViaRelayStorePallet; diff --git a/crates/kilt-dip-support/src/state_proofs.rs b/crates/kilt-dip-support/src/state_proofs.rs index 53099e6adb..1f4866ab85 100644 --- a/crates/kilt-dip-support/src/state_proofs.rs +++ b/crates/kilt-dip-support/src/state_proofs.rs @@ -302,7 +302,7 @@ pub(super) mod parachain { state_root: OutputOf, proof: impl IntoIterator>, ) -> Result { - let dip_commitment_storage_key = ParaInfo::dip_subject_storage_key(identifier); + let dip_commitment_storage_key = ParaInfo::dip_subject_storage_key(identifier, 0); let storage_proof = StorageProof::new(proof); let revealed_leaves = read_proof_check::( state_root, @@ -328,6 +328,7 @@ pub(super) mod parachain { use super::*; use hex_literal::hex; + use pallet_dip_provider::IdentityCommitmentVersion; use sp_core::H256; use sp_runtime::traits::BlakeTwo256; @@ -345,7 +346,10 @@ pub(super) mod parachain { type Identifier = (); type Key = StorageKey; - fn dip_subject_storage_key(_identifier: &Self::Identifier) -> Self::Key { + fn dip_subject_storage_key( + _identifier: &Self::Identifier, + _version: IdentityCommitmentVersion, + ) -> Self::Key { // system::eventCount() raw storage key let storage_key = hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec(); StorageKey(storage_key) diff --git a/crates/kilt-dip-support/src/traits.rs b/crates/kilt-dip-support/src/traits.rs index e23174a542..d3c013b1b5 100644 --- a/crates/kilt-dip-support/src/traits.rs +++ b/crates/kilt-dip-support/src/traits.rs @@ -17,6 +17,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use frame_system::pallet_prelude::BlockNumberFor; +use pallet_dip_provider::IdentityCommitmentVersion; use sp_core::storage::StorageKey; use sp_runtime::traits::{CheckedAdd, One, Zero}; use sp_std::marker::PhantomData; @@ -76,7 +77,7 @@ pub trait ProviderParachainStateInfo { type Hasher: sp_runtime::traits::Hash; type Identifier; - fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key; + fn dip_subject_storage_key(identifier: &Self::Identifier, version: IdentityCommitmentVersion) -> Self::Key; } pub struct ProviderParachainStateInfoViaProviderPallet(PhantomData); @@ -91,9 +92,9 @@ where type Identifier = T::Identifier; type Key = StorageKey; - fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key { + fn dip_subject_storage_key(identifier: &Self::Identifier, version: IdentityCommitmentVersion) -> Self::Key { StorageKey(pallet_dip_provider::IdentityCommitments::::hashed_key_for( - identifier, + identifier, version, )) } } diff --git a/dip-template/runtimes/dip-consumer/src/dip.rs b/dip-template/runtimes/dip-consumer/src/dip.rs index 40eb0bf100..91ca198c50 100644 --- a/dip-template/runtimes/dip-consumer/src/dip.rs +++ b/dip-template/runtimes/dip-consumer/src/dip.rs @@ -21,7 +21,7 @@ use dip_provider_runtime_template::{AccountId as ProviderAccountId, Runtime as P use frame_support::traits::Contains; use kilt_dip_support::{ traits::{DipCallOriginFilter, FrameSystemDidSignatureContext, ProviderParachainStateInfoViaProviderPallet}, - DipSiblingProviderStateProofVerifier, RococoStateRootsViaRelayStorePallet, + RococoStateRootsViaRelayStorePallet, VersionedDipSiblingProviderStateProofVerifier, }; use pallet_did_lookup::linkable_account::LinkableAccountId; use pallet_dip_consumer::traits::IdentityProofVerifier; @@ -32,7 +32,7 @@ use crate::{AccountId, DidIdentifier, Runtime, RuntimeCall, RuntimeOrigin}; pub type MerkleProofVerifierOutputOf = >::VerificationResult; -pub type ProofVerifier = DipSiblingProviderStateProofVerifier< +pub type ProofVerifier = VersionedDipSiblingProviderStateProofVerifier< RococoStateRootsViaRelayStorePallet, ConstU32<2_000>, ProviderParachainStateInfoViaProviderPallet, diff --git a/dip-template/runtimes/dip-provider/src/dip.rs b/dip-template/runtimes/dip-provider/src/dip.rs index bd86831553..720304f30b 100644 --- a/dip-template/runtimes/dip-provider/src/dip.rs +++ b/dip-template/runtimes/dip-provider/src/dip.rs @@ -18,7 +18,7 @@ use did::{DidRawOrigin, EnsureDidOrigin, KeyIdOf}; use pallet_did_lookup::linkable_account::LinkableAccountId; -use pallet_dip_provider::traits::IdentityProvider; +use pallet_dip_provider::{traits::IdentityProvider, IdentityCommitmentVersion}; use parity_scale_codec::{Decode, Encode}; use runtime_common::dip::{ did::LinkedDidInfoProviderOf, @@ -32,6 +32,7 @@ use crate::{AccountId, DidIdentifier, Hash, Runtime, RuntimeEvent}; #[derive(Encode, Decode, TypeInfo)] pub struct RuntimeApiDipProofRequest { pub(crate) identifier: DidIdentifier, + pub(crate) version: IdentityCommitmentVersion, pub(crate) keys: Vec>, pub(crate) accounts: Vec, pub(crate) should_include_web3_name: bool, diff --git a/dip-template/runtimes/dip-provider/src/lib.rs b/dip-template/runtimes/dip-provider/src/lib.rs index 578fb1939b..cc8320d55e 100644 --- a/dip-template/runtimes/dip-provider/src/lib.rs +++ b/dip-template/runtimes/dip-provider/src/lib.rs @@ -568,7 +568,6 @@ impl_runtime_apis! { } } - // TODO: Support generating different versions of the proof, based on the provided parameter impl kilt_runtime_api_dip_provider::DipProvider>, RuntimeApiDipProofError> for Runtime { fn generate_proof(request: RuntimeApiDipProofRequest) -> Result>, RuntimeApiDipProofError> { let linked_did_info = match ::IdentityProvider::retrieve(&request.identifier) { @@ -576,7 +575,7 @@ impl_runtime_apis! { Ok(None) => Err(RuntimeApiDipProofError::IdentityNotFound), Err(e) => Err(RuntimeApiDipProofError::IdentityProviderError(e)) }?; - DidMerkleRootGenerator::::generate_proof(&linked_did_info, request.keys.iter(), request.should_include_web3_name, request.accounts.iter()).map_err(RuntimeApiDipProofError::MerkleProofError) + DidMerkleRootGenerator::::generate_proof(&linked_did_info, request.version, request.keys.iter(), request.should_include_web3_name, request.accounts.iter()).map_err(RuntimeApiDipProofError::MerkleProofError) } } } diff --git a/pallets/pallet-dip-provider/Cargo.toml b/pallets/pallet-dip-provider/Cargo.toml index 5e22e357a1..8c078fbc52 100644 --- a/pallets/pallet-dip-provider/Cargo.toml +++ b/pallets/pallet-dip-provider/Cargo.toml @@ -19,6 +19,7 @@ frame-support.workspace = true frame-system.workspace = true parity-scale-codec = {workspace = true, features = ["derive"]} scale-info = {workspace = true, features = ["derive"]} +sp-io.workspace = true sp-std.workspace = true [features] diff --git a/pallets/pallet-dip-provider/src/lib.rs b/pallets/pallet-dip-provider/src/lib.rs index ad17b78e4e..826fd170ac 100644 --- a/pallets/pallet-dip-provider/src/lib.rs +++ b/pallets/pallet-dip-provider/src/lib.rs @@ -31,14 +31,23 @@ pub mod pallet { use frame_support::{pallet_prelude::*, traits::EnsureOrigin}; use frame_system::pallet_prelude::*; use parity_scale_codec::FullCodec; + use sp_io::MultiRemovalResults; use sp_std::fmt::Debug; use crate::traits::{IdentityCommitmentGenerator, IdentityProvider, SubmitterInfo}; pub type IdentityOf = <::IdentityProvider as IdentityProvider<::Identifier>>::Success; + pub type IdentityCommitmentVersion = u16; + pub const LATEST_COMMITMENT_VERSION: IdentityCommitmentVersion = 0; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + #[derive(Encode, Decode, RuntimeDebug, TypeInfo, Clone, PartialEq)] + pub enum VersionOrLimit { + Version(IdentityCommitmentVersion), + Limit(u32), + } + #[pallet::config] pub trait Config: frame_system::Config { type CommitOriginCheck: EnsureOrigin; @@ -59,8 +68,14 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn identity_commitments)] - pub type IdentityCommitments = - StorageMap<_, Twox64Concat, ::Identifier, ::IdentityCommitment>; + pub type IdentityCommitments = StorageDoubleMap< + _, + Twox64Concat, + ::Identifier, + Twox64Concat, + IdentityCommitmentVersion, + ::IdentityCommitment, + >; #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -72,6 +87,11 @@ pub mod pallet { IdentityCommitted { identifier: T::Identifier, commitment: T::IdentityCommitment, + version: IdentityCommitmentVersion, + }, + VersionedIdentityDeleted { + identifier: T::Identifier, + version: IdentityCommitmentVersion, }, IdentityDeleted { identifier: T::Identifier, @@ -80,6 +100,8 @@ pub mod pallet { #[pallet::error] pub enum Error { + IdentityNotFound, + LimitTooLow, IdentityProvider(u16), IdentityCommitmentGenerator(u16), } @@ -89,32 +111,70 @@ pub mod pallet { #[pallet::call_index(0)] // TODO: Update weight #[pallet::weight(0)] - pub fn commit_identity(origin: OriginFor, identifier: T::Identifier) -> DispatchResult { + pub fn commit_identity( + origin: OriginFor, + identifier: T::Identifier, + version: Option, + ) -> DispatchResult { // TODO: use dispatcher to get deposit let _dispatcher = T::CommitOriginCheck::ensure_origin(origin).map(|e: ::CommitOrigin| e.submitter())?; - let identity_commitment: Option = match T::IdentityProvider::retrieve(&identifier) { - Ok(Some(identity)) => T::IdentityCommitmentGenerator::generate_commitment(&identifier, &identity) - .map(Some) - .map_err(|error| Error::::IdentityCommitmentGenerator(error.into())), - Ok(None) => Ok(None), + let commitment_version = version.unwrap_or(LATEST_COMMITMENT_VERSION); + let commitment = match T::IdentityProvider::retrieve(&identifier) { + Ok(Some(identity)) => { + T::IdentityCommitmentGenerator::generate_commitment(&identifier, &identity, commitment_version) + .map_err(|error| Error::::IdentityCommitmentGenerator(error.into())) + } + Ok(None) => Err(Error::::IdentityNotFound), Err(error) => Err(Error::::IdentityProvider(error.into())), }?; - if let Some(commitment) = identity_commitment { - // TODO: Take deposit (once 0.9.42 PR is merged into develop) - IdentityCommitments::::insert(&identifier, commitment.clone()); - Self::deposit_event(Event::::IdentityCommitted { identifier, commitment }); - } else { - // TODO: Release deposit (once 0.9.42 PR is merged into develop) - IdentityCommitments::::remove(&identifier); - Self::deposit_event(Event::::IdentityDeleted { identifier }); - } + // TODO: Take deposit (once 0.9.42 PR is merged into develop) + IdentityCommitments::::insert(&identifier, commitment_version, commitment.clone()); + Self::deposit_event(Event::::IdentityCommitted { + identifier, + commitment, + version: commitment_version, + }); + Ok(()) + } + + #[pallet::call_index(1)] + // TODO: Update weight + #[pallet::weight(0)] + pub fn delete_identity_commitment( + origin: OriginFor, + identifier: T::Identifier, + version_or_limit: VersionOrLimit, + ) -> DispatchResult { + let _dispatcher = + T::CommitOriginCheck::ensure_origin(origin).map(|e: ::CommitOrigin| e.submitter())?; + match version_or_limit { + VersionOrLimit::Version(version) => { + let commitment = IdentityCommitments::::take(&identifier, version); + match commitment { + Some(_) => Err(Error::::IdentityNotFound), + None => { + Self::deposit_event(Event::::VersionedIdentityDeleted { identifier, version }); + Ok(()) + } + } + } + VersionOrLimit::Limit(limit) => { + let MultiRemovalResults { maybe_cursor, .. } = + IdentityCommitments::::clear_prefix(&identifier, limit, None); + match maybe_cursor { + Some(_) => Err(Error::::LimitTooLow), + None => { + Self::deposit_event(Event::::IdentityDeleted { identifier }); + Ok(()) + } + } + } + }?; Ok(()) } - // TODO: Add extrinsic to remove commitment without requiring the identity to be - // deleted. } } diff --git a/pallets/pallet-dip-provider/src/traits.rs b/pallets/pallet-dip-provider/src/traits.rs index 5f0d137963..76b742e129 100644 --- a/pallets/pallet-dip-provider/src/traits.rs +++ b/pallets/pallet-dip-provider/src/traits.rs @@ -22,11 +22,17 @@ pub use identity_generation::*; pub mod identity_generation { use sp_std::marker::PhantomData; + use crate::IdentityCommitmentVersion; + pub trait IdentityCommitmentGenerator { type Error; type Output; - fn generate_commitment(identifier: &Identifier, identity: &Identity) -> Result; + fn generate_commitment( + identifier: &Identifier, + identity: &Identity, + version: IdentityCommitmentVersion, + ) -> Result; } // Implement the `IdentityCommitmentGenerator` by returning the `Default` value @@ -41,7 +47,11 @@ pub mod identity_generation { type Error = (); type Output = Output; - fn generate_commitment(_identifier: &Identifier, _identity: &Identity) -> Result { + fn generate_commitment( + _identifier: &Identifier, + _identity: &Identity, + _version: IdentityCommitmentVersion, + ) -> Result { Ok(Output::default()) } } diff --git a/runtimes/common/src/dip/merkle.rs b/runtimes/common/src/dip/merkle.rs index 0059d267ae..d7af9c87b5 100644 --- a/runtimes/common/src/dip/merkle.rs +++ b/runtimes/common/src/dip/merkle.rs @@ -20,7 +20,7 @@ use frame_support::RuntimeDebug; use frame_system::pallet_prelude::BlockNumberFor; use kilt_dip_support::merkle::{DidKeyMerkleKey, DidKeyMerkleValue, DidMerkleProof}; use pallet_did_lookup::linkable_account::LinkableAccountId; -use pallet_dip_provider::traits::IdentityCommitmentGenerator; +use pallet_dip_provider::{traits::IdentityCommitmentGenerator, IdentityCommitmentVersion}; use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; use sp_std::{borrow::ToOwned, marker::PhantomData, vec::Vec}; @@ -50,6 +50,7 @@ pub struct CompleteMerkleProof { #[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo, PartialEq)] pub enum DidMerkleProofError { + UnsupportedVersion, DidNotFound, KeyNotFound, LinkedAccountNotFound, @@ -60,50 +61,40 @@ pub enum DidMerkleProofError { impl From for u16 { fn from(value: DidMerkleProofError) -> Self { match value { - DidMerkleProofError::DidNotFound => 0, - DidMerkleProofError::KeyNotFound => 1, - DidMerkleProofError::LinkedAccountNotFound => 2, - DidMerkleProofError::Web3NameNotFound => 3, + DidMerkleProofError::UnsupportedVersion => 0, + DidMerkleProofError::DidNotFound => 1, + DidMerkleProofError::KeyNotFound => 2, + DidMerkleProofError::LinkedAccountNotFound => 3, + DidMerkleProofError::Web3NameNotFound => 4, DidMerkleProofError::Internal => u16::MAX, } } } -pub struct DidMerkleRootGenerator(PhantomData); +pub mod v0 { + use super::*; -type ProofLeafOf = RevealedDidMerkleProofLeaf< - KeyIdOf, - ::AccountId, - BlockNumberFor, - ::Web3Name, - LinkableAccountId, ->; + type ProofLeafOf = RevealedDidMerkleProofLeaf< + KeyIdOf, + ::AccountId, + BlockNumberFor, + ::Web3Name, + LinkableAccountId, + >; -impl DidMerkleRootGenerator -where - T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, -{ - // Calls the function in the `sp_trie` crate to generate the merkle root given - // the provided `DidDetails`. - // Each key in the merkle tree is added in the following way: - // - keys in the `public_keys` map are added by value in the merkle tree, with - // the leaf key being the key ID and the value being the key details - // - keys everywhere else in the DidDetails are added by reference, with the - // leaf key being the encoding of the tuple (keyID, key relationship) and the - // value being hte empty tuple - // A valid proof will contain a leaf with the key details for each reference - // leaf, with multiple reference leaves potentially referring to the same - // details leaf, as we already do with out `DidDetails` type. - fn calculate_root_with_db( - identity: &LinkedDidInfoOf, - db: &mut MemoryDB, - ) -> Result { + pub(super) fn calculate_root_with_db( + identity: &LinkedDidInfoOf, + db: &mut MemoryDB, + ) -> Result + where + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, + { // Fails if the DID details do not exist. let (Some(did_details), web3_name, linked_accounts) = (&identity.a, &identity.b, &identity.c) else { return Err(DidMerkleProofError::DidNotFound); }; - let mut trie = TrieHash::>::default(); - let mut trie_builder = TrieDBMutBuilder::>::new(db, &mut trie).build(); + let mut trie = TrieHash::>::default(); + let mut trie_builder = TrieDBMutBuilder::>::new(db, &mut trie).build(); // Authentication key let auth_key_details = did_details @@ -113,7 +104,7 @@ where log::error!("Authentication key should be part of the public keys."); DidMerkleProofError::Internal })?; - let auth_leaf = ProofLeafOf::::DidKey( + let auth_leaf = ProofLeafOf::::DidKey( DidKeyMerkleKey( did_details.authentication_key, DidVerificationKeyRelationship::Authentication.into(), @@ -135,7 +126,7 @@ where log::error!("Attestation key should be part of the public keys."); DidMerkleProofError::Internal })?; - let att_leaf = ProofLeafOf::::DidKey( + let att_leaf = ProofLeafOf::::DidKey( (att_key_id, DidVerificationKeyRelationship::AssertionMethod.into()).into(), att_key_details.clone().into(), ); @@ -155,7 +146,7 @@ where log::error!("Delegation key should be part of the public keys."); DidMerkleProofError::Internal })?; - let del_leaf = ProofLeafOf::::DidKey( + let del_leaf = ProofLeafOf::::DidKey( (del_key_id, DidVerificationKeyRelationship::CapabilityDelegation.into()).into(), del_key_details.clone().into(), ); @@ -178,7 +169,7 @@ where log::error!("Key agreement key should be part of the public keys."); DidMerkleProofError::Internal })?; - let enc_leaf = ProofLeafOf::::DidKey( + let enc_leaf = ProofLeafOf::::DidKey( (*id, DidKeyRelationship::Encryption).into(), key_agreement_details.clone().into(), ); @@ -199,7 +190,8 @@ where linked_accounts .iter() .try_for_each(|linked_account| -> Result<(), DidMerkleProofError> { - let linked_account_leaf = ProofLeafOf::::LinkedAccount(linked_account.clone().into(), ().into()); + let linked_account_leaf = + ProofLeafOf::::LinkedAccount(linked_account.clone().into(), ().into()); trie_builder .insert( linked_account_leaf.encoded_key().as_slice(), @@ -218,7 +210,7 @@ where // Web3name, if present if let Some(web3name_details) = web3_name { - let web3_name_leaf = ProofLeafOf::::Web3Name( + let web3_name_leaf = ProofLeafOf::::Web3Name( web3name_details.web3_name.clone().into(), web3name_details.claimed_at.into(), ); @@ -240,19 +232,15 @@ where Ok(trie_builder.root().to_owned()) } - // Only used for testing and as part of the features exposed by the runtime API - // of the provider. Given the provided `DidDetails` and a list of key IDs, it - // generates a merkle proof which only reveals the details of the provided key - // IDs. - #[allow(clippy::result_unit_err)] - pub fn generate_proof<'a, K, A>( - identity: &LinkedDidInfoOf, + pub(super) fn generate_proof<'a, Runtime, K, A>( + identity: &LinkedDidInfoOf, key_ids: K, should_include_web3_name: bool, account_ids: A, - ) -> Result>, DidMerkleProofError> + ) -> Result>, DidMerkleProofError> where - K: Iterator>, + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, + K: Iterator>, A: Iterator, { // Fails if the DID details do not exist. @@ -261,7 +249,7 @@ where }; let mut db = MemoryDB::default(); - let root = Self::calculate_root_with_db(identity, &mut db)?; + let root = calculate_root_with_db(identity, &mut db)?; let mut leaves = key_ids .map(|key_id| -> Result<_, DidMerkleProofError> { @@ -271,7 +259,8 @@ where .ok_or(DidMerkleProofError::KeyNotFound)?; // Create the merkle leaf key depending on the relationship of the key to the // DID document. - let did_key_merkle_key: DidKeyMerkleKey> = if *key_id == did_details.authentication_key { + let did_key_merkle_key: DidKeyMerkleKey> = if *key_id == did_details.authentication_key + { Ok((*key_id, DidVerificationKeyRelationship::Authentication.into()).into()) } else if Some(*key_id) == did_details.attestation_key { Ok((*key_id, DidVerificationKeyRelationship::AssertionMethod.into()).into()) @@ -321,32 +310,73 @@ where }?; let encoded_keys: Vec> = leaves.iter().map(|l| l.encoded_key()).collect(); - let proof = generate_trie_proof::, _, _, _>(&db, root, &encoded_keys).map_err(|_| { - log::error!( - "Failed to generate a merkle proof for the encoded keys: {:#?}", - encoded_keys - ); - DidMerkleProofError::Internal - })?; + let proof = + generate_trie_proof::, _, _, _>(&db, root, &encoded_keys).map_err(|_| { + log::error!( + "Failed to generate a merkle proof for the encoded keys: {:#?}", + encoded_keys + ); + DidMerkleProofError::Internal + })?; Ok(CompleteMerkleProof { root, - proof: DidMerkleProofOf:: { + proof: DidMerkleProofOf:: { blinded: proof, revealed: leaves.into_iter().collect(), }, }) } + + pub(super) fn generate_commitment( + identity: &LinkedDidInfoOf, + ) -> Result + where + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, + { + let mut db = MemoryDB::default(); + calculate_root_with_db(identity, &mut db) + } } -impl IdentityCommitmentGenerator> for DidMerkleRootGenerator +pub struct DidMerkleRootGenerator(PhantomData); + +impl IdentityCommitmentGenerator> for DidMerkleRootGenerator where - T: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, { type Error = DidMerkleProofError; - type Output = T::Hash; + type Output = Runtime::Hash; - fn generate_commitment(_identifier: &DidIdentifier, identity: &LinkedDidInfoOf) -> Result { - let mut db = MemoryDB::default(); - Self::calculate_root_with_db(identity, &mut db) + fn generate_commitment( + _identifier: &DidIdentifier, + identity: &LinkedDidInfoOf, + version: IdentityCommitmentVersion, + ) -> Result { + match version { + 0 => v0::generate_commitment::(identity), + _ => Err(DidMerkleProofError::UnsupportedVersion), + } + } +} + +impl DidMerkleRootGenerator +where + Runtime: did::Config + pallet_did_lookup::Config + pallet_web3_names::Config, +{ + pub fn generate_proof<'a, K, A>( + identity: &LinkedDidInfoOf, + version: IdentityCommitmentVersion, + key_ids: K, + should_include_web3_name: bool, + account_ids: A, + ) -> Result>, DidMerkleProofError> + where + K: Iterator>, + A: Iterator, + { + match version { + 0 => v0::generate_proof(identity, key_ids, should_include_web3_name, account_ids), + _ => Err(DidMerkleProofError::UnsupportedVersion), + } } }