Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
54a23a5
Refactor pallet-dip-provider
ntn-x2 Jul 11, 2023
25b3cb6
Remove unused dependencies from pallet-dip-provider
ntn-x2 Jul 11, 2023
c7ef216
mIntroduce state proofs in pallet-dip-consumer
ntn-x2 Jul 11, 2023
06de832
Temporarly fix kilt-dip-support to compile
ntn-x2 Jul 11, 2023
dda48d6
Whole project compiling
ntn-x2 Jul 11, 2023
cfe1fb3
Add parachain root state proof verifier
ntn-x2 Jul 12, 2023
77b2a48
Proof of storage entry for parachain also working
ntn-x2 Jul 12, 2023
4fd3f06
Half-way
ntn-x2 Jul 12, 2023
a9ca939
Before replacing 'read_proof_check'
ntn-x2 Jul 13, 2023
81ea88c
Ported the proof verification for no_std
ntn-x2 Jul 13, 2023
e8919f1
Refactoring on the way
ntn-x2 Jul 13, 2023
8808f14
New overarching verifier
ntn-x2 Jul 13, 2023
16b1bc9
Whole workspace compiling (not run/tested yet)
ntn-x2 Jul 13, 2023
47481e0
Keep track of the last 2 relay state roots to allow for proof creation
ntn-x2 Jul 14, 2023
50edc7b
Compiles
ntn-x2 Jul 17, 2023
f542428
Use relay block height instead of block hash
ntn-x2 Jul 18, 2023
318d765
Cleaning before kilt-dip-support
ntn-x2 Jul 20, 2023
7b67a57
On the way there
ntn-x2 Jul 20, 2023
d7dda64
Step n.2
ntn-x2 Jul 20, 2023
6b94cbf
all good
ntn-x2 Jul 21, 2023
622c046
Everything compiling
ntn-x2 Jul 21, 2023
2718f95
Still working
ntn-x2 Jul 21, 2023
f00cf33
Refactor complete
ntn-x2 Jul 21, 2023
f91693d
Pallet updated
ntn-x2 Jul 21, 2023
d81ac18
Renaming
ntn-x2 Jul 21, 2023
22b577c
Change SignedExtra to not be Optional
ntn-x2 Jul 21, 2023
358c095
clippy
ntn-x2 Jul 21, 2023
6020f80
Remove unnecessary derive
ntn-x2 Jul 21, 2023
408f5b9
Remove XCM from templates
ntn-x2 Jul 21, 2023
4dfc7a3
Remove unwanted file
ntn-x2 Jul 21, 2023
ff68537
Merge branch 'aa/dip' into aa/state-proofs
ntn-x2 Aug 10, 2023
9cbbd54
feat: add support for relay chain (#553)
ntn-x2 Aug 23, 2023
9d36356
feat: add relaychain support (#563)
ntn-x2 Sep 20, 2023
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
Prev Previous commit
Next Next commit
Half-way
  • Loading branch information
ntn-x2 committed Jul 12, 2023
commit 4fd3f066d04dedcf68b6f6e0a3f2c7ee49702db0
133 changes: 67 additions & 66 deletions crates/kilt-dip-support/src/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@

use did::{did_details::DidPublicKeyDetails, DidVerificationKeyRelationship};
use frame_support::{traits::ConstU32, RuntimeDebug};
use pallet_dip_consumer::traits::IdentityProofVerifier;
use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::BoundedVec;
use sp_runtime::{BoundedVec, SaturatedConversion};
use sp_std::{fmt::Debug, marker::PhantomData, vec::Vec};
use sp_trie::{verify_trie_proof, LayoutV1};

pub type BlindedValue = Vec<u8>;

Expand Down Expand Up @@ -259,7 +260,7 @@ impl<
// TODO: Proper error handling
type Error = ();
type Proof = MerkleProof<Vec<Vec<u8>>, ProofLeaf<KeyId, BlockNumber, Web3Name, LinkedAccountId>>;
type IdentityDetails = Details;
type IdentityDetails = IdentityDetails<Hasher::Out, Details>;
type Submitter = AccountId;
type VerificationResult = VerificationResult<
KeyId,
Expand All @@ -274,69 +275,69 @@ impl<
_call: &Call,
_subject: &Subject,
_submitter: &Self::Submitter,
_identity_details: &mut Option<Self::IdentityDetails>,
_proof: &Self::Proof,
identity_details: &mut Option<Self::IdentityDetails>,
proof: &Self::Proof,
) -> Result<Self::VerificationResult, Self::Error> {
Err(())
// // TODO: more efficient by removing cloning and/or collecting.
// // Did not find another way of mapping a Vec<(Vec<u8>, Vec<u8>)> to a
// // Vec<(Vec<u8>, Option<Vec<u8>>)>.
// let proof_leaves = proof
// .revealed
// .iter()
// .map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value())))
// .collect::<Vec<(Vec<u8>, Option<Vec<u8>>)>>();
// verify_trie_proof::<LayoutV1<Hasher>, _, _, _>(
// &identity_details.digest.clone().into(),
// &proof.blinded,
// &proof_leaves,
// )
// .map_err(|_| ())?;

// // At this point, we know the proof is valid. We just need to map the
// revealed // leaves to something the consumer can easily operate on.
// #[allow(clippy::type_complexity)]
// let (did_keys, web3_name, linked_accounts): (
// BoundedVec<RevealedDidKey<KeyId, BlockNumber>,
// ConstU32<MAX_REVEALED_KEYS_COUNT>>, Option<RevealedWeb3Name<Web3Name,
// BlockNumber>>, BoundedVec<LinkedAccountId,
// ConstU32<MAX_REVEALED_ACCOUNTS_COUNT>>, ) = proof.revealed.iter().
// try_fold( (
// BoundedVec::with_bounded_capacity(MAX_REVEALED_KEYS_COUNT.
// saturated_into()), None,
// BoundedVec::with_bounded_capacity(MAX_REVEALED_ACCOUNTS_COUNT.
// saturated_into()), ),
// |(mut keys, web3_name, mut linked_accounts), leaf| match leaf {
// ProofLeaf::DidKey(key_id, key_value) => {
// keys.try_push(RevealedDidKey {
// // TODO: Avoid cloning if possible
// id: key_id.0.clone(),
// relationship: key_id.1,
// details: key_value.0.clone(),
// })
// .map_err(|_| ())?;
// Ok::<_, ()>((keys, web3_name, linked_accounts))
// }
// // TODO: Avoid cloning if possible
// ProofLeaf::Web3Name(revealed_web3_name, details) => Ok((
// keys,
// Some(RevealedWeb3Name {
// web3_name: revealed_web3_name.0.clone(),
// claimed_at: details.0.clone(),
// }),
// linked_accounts,
// )),
// ProofLeaf::LinkedAccount(account_id, _) => {
// linked_accounts.try_push(account_id.0.clone()).map_err(|_| ())?;
// Ok::<_, ()>((keys, web3_name, linked_accounts))
// }
// },
// )?;

// Ok(VerificationResult {
// did_keys,
// web3_name,
// linked_accounts,
// })
// TODO: more efficient by removing cloning and/or collecting.
// Did not find another way of mapping a Vec<(Vec<u8>, Vec<u8>)> to a
// Vec<(Vec<u8>, Option<Vec<u8>>)>.
let proof_leaves = proof
.revealed
.iter()
.map(|leaf| (leaf.encoded_key(), Some(leaf.encoded_value())))
.collect::<Vec<(Vec<u8>, Option<Vec<u8>>)>>();
let Some(identity_details) = identity_details else { return Err(()) };
verify_trie_proof::<LayoutV1<Hasher>, _, _, _>(
&identity_details.digest.clone().into(),
&proof.blinded,
&proof_leaves,
)
.map_err(|_| ())?;

// At this point, we know the proof is valid. We just need to map the revealed
// leaves to something the consumer can easily operate on.
#[allow(clippy::type_complexity)]
let (did_keys, web3_name, linked_accounts): (
BoundedVec<RevealedDidKey<KeyId, BlockNumber>, ConstU32<MAX_REVEALED_KEYS_COUNT>>,
Option<RevealedWeb3Name<Web3Name, BlockNumber>>,
BoundedVec<LinkedAccountId, ConstU32<MAX_REVEALED_ACCOUNTS_COUNT>>,
) = proof.revealed.iter().try_fold(
(
BoundedVec::with_bounded_capacity(MAX_REVEALED_KEYS_COUNT.saturated_into()),
None,
BoundedVec::with_bounded_capacity(MAX_REVEALED_ACCOUNTS_COUNT.saturated_into()),
),
|(mut keys, web3_name, mut linked_accounts), leaf| match leaf {
ProofLeaf::DidKey(key_id, key_value) => {
keys.try_push(RevealedDidKey {
// TODO: Avoid cloning if possible
id: key_id.0.clone(),
relationship: key_id.1,
details: key_value.0.clone(),
})
.map_err(|_| ())?;
Ok::<_, ()>((keys, web3_name, linked_accounts))
}
// TODO: Avoid cloning if possible
ProofLeaf::Web3Name(revealed_web3_name, details) => Ok((
keys,
Some(RevealedWeb3Name {
web3_name: revealed_web3_name.0.clone(),
claimed_at: details.0.clone(),
}),
linked_accounts,
)),
ProofLeaf::LinkedAccount(account_id, _) => {
linked_accounts.try_push(account_id.0.clone()).map_err(|_| ())?;
Ok::<_, ()>((keys, web3_name, linked_accounts))
}
},
)?;

Ok(VerificationResult {
did_keys,
web3_name,
linked_accounts,
})
}
}
83 changes: 71 additions & 12 deletions crates/kilt-dip-support/src/new_stuff.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,79 @@
use parity_scale_codec::Decode;
use sp_runtime::traits::Hash;
use pallet_dip_consumer::{identity::IdentityDetails, traits::IdentityProofVerifier};
use parity_scale_codec::{Decode, HasCompact};
use sp_core::{Get, U256};
use sp_runtime::{generic::Header, traits::Hash};
use sp_state_machine::read_proof_check;
use sp_std::marker::PhantomData;
use sp_trie::StorageProof;

pub struct DipProof<InnerProof> {
para_root_proof: Vec<Vec<u8>>,
dip_commitment_proof: Vec<Vec<u8>>,
dip_proof: InnerProof,
}

pub struct StateProofDipVerifier<ProviderParaId, RelayInfoProvider, ProviderParaInfoProvider, DipVerifier>(
PhantomData<(ProviderParaId, RelayInfoProvider, ProviderParaInfoProvider, DipVerifier)>,
);

impl<Call, Subject, ProviderParaId, RelayInfoProvider, ProviderParaInfoProvider, DipVerifier>
IdentityProofVerifier<Call, Subject>
for StateProofDipVerifier<ProviderParaId, RelayInfoProvider, ProviderParaInfoProvider, DipVerifier>
where
ProviderParaId: Get<RelayInfoProvider::ParaId>,

RelayInfoProvider: relay_chain::RelayChainStateInfoProvider,
RelayInfoProvider::Hasher: 'static,
<RelayInfoProvider::Hasher as Hash>::Output: Ord,
RelayInfoProvider::BlockNumber: Copy + Into<U256> + TryFrom<U256> + HasCompact,
RelayInfoProvider::Key: AsRef<[u8]>,

ProviderParaInfoProvider: parachain::ParachainStateInfoProvider<Identifier = Subject>,
ProviderParaInfoProvider::Hasher: 'static,
<ProviderParaInfoProvider::Hasher as Hash>::Output: Ord,
ProviderParaInfoProvider::Commitment: Decode,
ProviderParaInfoProvider::Key: AsRef<[u8]>,

DipVerifier: IdentityProofVerifier<Call, Subject>,
{
type Error = ();
type IdentityDetails = IdentityDetails<DipVerifier>;
type Proof = DipProof<DipVerifier::Proof>;
type Submitter = DipVerifier::Submitter;
type VerificationResult = DipVerifier::VerificationResult;

fn verify_proof_for_call_against_details(
call: &Call,
subject: &Subject,
submitter: &Self::Submitter,
identity_details: &mut Option<Self::IdentityDetails>,
proof: &Self::Proof,
) -> Result<Self::VerificationResult, Self::Error> {
let provider_parachain_header =
relay_chain::ParachainHeadProofVerifier::<RelayInfoProvider>::verify_proof_for_parachain(
&ProviderParaId::get(),
proof.para_root_proof,
)?;
let provider_parachain_root_state = provider_parachain_header.state_root;
let subject_identity_commitment =
parachain::DipCommitmentValueProofVerifier::<ProviderParaInfoProvider>::verify_proof_for_identifier(
subject,
proof.dip_commitment_proof,
)?;
// TODO: Call the third and last step for the DIP merkle verification.
}
}

pub mod relay_chain {
use super::*;

pub trait RelayChainStateInfoProvider {
type BlockNumber;
type Key;
type Hasher: Hash;
type Header;
type ParaId;

fn parachain_head_storage_key(para_id: Self::ParaId) -> Self::Key;
fn parachain_head_storage_key(para_id: &Self::ParaId) -> Self::Key;
fn state_root() -> <Self::Hasher as Hash>::Output;
}

Expand All @@ -24,13 +84,13 @@ pub mod relay_chain {
RelayInfoProvider: RelayChainStateInfoProvider,
RelayInfoProvider::Hasher: 'static,
<RelayInfoProvider::Hasher as Hash>::Output: Ord,
RelayInfoProvider::Header: Decode,
RelayInfoProvider::BlockNumber: Copy + Into<U256> + TryFrom<U256> + HasCompact,
RelayInfoProvider::Key: AsRef<[u8]>,
{
pub fn verify_proof_for_parachain(
para_id: RelayInfoProvider::ParaId,
para_id: &RelayInfoProvider::ParaId,
proof: impl IntoIterator<Item = Vec<u8>>,
) -> Result<RelayInfoProvider::Header, ()> {
) -> Result<Header<RelayInfoProvider::BlockNumber, RelayInfoProvider::Hasher>, ()> {
let relay_state_root = RelayInfoProvider::state_root();
let parachain_storage_key = RelayInfoProvider::parachain_head_storage_key(para_id);
let storage_proof = StorageProof::new(proof);
Expand All @@ -46,7 +106,7 @@ pub mod relay_chain {
let Some(Some(encoded_head)) = revealed_leaves.get(parachain_storage_key.as_ref()) else { return Err(()) };
// TODO: Figure out why RPC call returns 2 bytes in front which we don't need
let mut unwrapped_head = &encoded_head[2..];
RelayInfoProvider::Header::decode(&mut unwrapped_head).map_err(|_| ())
Header::decode(&mut unwrapped_head).map_err(|_| ())
}
}

Expand All @@ -58,15 +118,14 @@ pub mod relay_chain {
use parity_scale_codec::Encode;
use polkadot_primitives::BlakeTwo256;
use sp_core::{storage::StorageKey, H256};
use sp_runtime::generic::Header;

// Polkadot block n: 16_363_919,
// hash 0x18e90e9aa8e3b063f60386ba1b0415111798e72d01de58b1438d620d42f58e39
struct StaticPolkadotInfoProvider;

impl RelayChainStateInfoProvider for StaticPolkadotInfoProvider {
type BlockNumber = u32;
type Hasher = BlakeTwo256;
type Header = Header<u32, Self::Hasher>;
type Key = StorageKey;
type ParaId = u32;

Expand Down Expand Up @@ -124,7 +183,7 @@ pub mod parachain {
type Hasher: Hash;
type Identifier;

fn dip_subject_storage_key(identifier: Self::Identifier) -> Self::Key;
fn dip_subject_storage_key(identifier: &Self::Identifier) -> Self::Key;
fn state_root() -> <Self::Hasher as Hash>::Output;
}

Expand All @@ -139,7 +198,7 @@ pub mod parachain {
ParaInfoProvider::Key: AsRef<[u8]>,
{
pub fn verify_proof_for_identifier(
identifier: ParaInfoProvider::Identifier,
identifier: &ParaInfoProvider::Identifier,
proof: impl IntoIterator<Item = Vec<u8>>,
) -> Result<ParaInfoProvider::Commitment, ()> {
let parachain_state_root = ParaInfoProvider::state_root();
Expand Down
26 changes: 26 additions & 0 deletions pallets/pallet-dip-consumer/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,29 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

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

use frame_support::RuntimeDebug;
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;

/// The identity entry for any given user that uses the DIP protocol.
#[derive(Encode, Decode, MaxEncodedLen, Default, TypeInfo, RuntimeDebug)]
pub struct IdentityDetails<Digest, Details> {
/// The identity digest information, typically used to verify identity
/// proofs.
pub digest: Digest,
/// The details related to the user, stored in the pallet storage.
pub details: Details,
}

impl<Digest, Details> From<Digest> for IdentityDetails<Digest, Details>
where
Details: Default,
{
fn from(value: Digest) -> Self {
Self {
digest: value,
details: Details::default(),
}
}
}
10 changes: 5 additions & 5 deletions pallets/pallet-dip-consumer/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use sp_std::marker::PhantomData;

pub trait IdentityProofVerifier<Call, Subject> {
type Error;
type Proof;
type IdentityDetails;
type Proof;
type Submitter;
type VerificationResult;

Expand All @@ -35,13 +35,13 @@ pub trait IdentityProofVerifier<Call, Subject> {
}

// Always returns success.
pub struct SuccessfulProofVerifier<Proof, ProofEntry, Submitter>(PhantomData<(Proof, ProofEntry, Submitter)>);
impl<Call, Subject, Proof, ProofEntry, Submitter> IdentityProofVerifier<Call, Subject>
for SuccessfulProofVerifier<Proof, ProofEntry, Submitter>
pub struct SuccessfulProofVerifier<IdentityDetails, Proof, Submitter>(PhantomData<(IdentityDetails, Proof, Submitter)>);
impl<Call, Subject, IdentityDetails, Proof, Submitter> IdentityProofVerifier<Call, Subject>
for SuccessfulProofVerifier<IdentityDetails, Proof, Submitter>
{
type Error = ();
type IdentityDetails = IdentityDetails;
type Proof = Proof;
type IdentityDetails = ProofEntry;
type Submitter = Submitter;
type VerificationResult = ();

Expand Down