Skip to content

Commit

Permalink
feat: add merkleization of DID documents (#492)
Browse files Browse the repository at this point in the history
Fixes KILTprotocol/ticket#2557 and fixes
KILTprotocol/ticket#2556.

This PR builds on top of the shell PR, and adds support for Merkle proof
for DID documents.

## Merkle proof structure

A DID merkle proof is, at the core, an order set of (key, value) pairs,
on which proof-of-inclusion and proof-of-non-inclusion can be performed.
This PR generates and validates merkle proofs where leaves are of two
types:

- a DID key reference leave, whose key is the tuple (key ID, key
relationship) and the value is an empty tuple
- a DID key details leave, whose key is the key ID and the value is the
key details

For each key reference leaf with a given key ID, the proof also has to
contain a key details leaf whose key is the key ID. Multiple reference
leaves can reference the same key details leaf, optimising the storage
size.

## New runtime APIs

There is a new runtime API which the DIP sender would expose, and that
allows anyone to generate a merkle proof for a given DID identifier and
set of key IDs. The result contains the merkle root (which must match
what other chains have stored in their `pallet-dip-receiver` map), and a
merkle proof, which includes blinded values and a set of key reference
and key details leaves for the keys identified by the provided key IDs.

## How to test

The setup flow is similar to that of
#489.
Specifically:

- Set up the local Rococo network onboarding the sender and receiver
chains with para IDs 2_000 and 2_001 respectively
- Open an HRMP channel from sender 2_000 to receiver 2_001
- Create a DID on the sender chain, e.g., using the
[kilt-did-utilities](https://github.com/KILTprotocol/kilt-did-utilities)
tool
![Screenshot 2023-03-27 at 10 00
48](https://user-images.githubusercontent.com/6704504/227900994-41f0f355-84bd-4b8a-a2a8-3a9c74447e59.png)
- Push the identity of the DID to the receiver chain via the
`pallet-dip-sender` extrinsic
![Screenshot 2023-03-27 at 10 01
13](https://user-images.githubusercontent.com/6704504/227901150-7e8c9c9d-8aac-4739-8ad3-fad4ba6ff5f8.png)
- Call the runtime API to generate a proof for the created DID with some
keys revealed
![Screenshot 2023-03-27 at 10 01
40](https://user-images.githubusercontent.com/6704504/227901309-94b4dbc9-ca83-4541-820d-d1bec6adc6f0.png)
- Use the generated proof to dispatch an extrinsic on the receiving
chain

### How to use the runtime API with polkadot apps

There is currently no support for the new runtime API in the public
polkadot apps instance. To use the runtime APIs from UI, please use [our
fork from the aa/dip-sender-template
branch](https://github.com/KILTprotocol/polkadot-apps/tree/aa/dip-sender-template),
by running `yarn && yarn build && yarn start`, then connecting to the
sender node WS socket.
For runtime augmentation within a Node script, please use our [SDK repo
from the aa/dip-merkle-proof
branch](https://github.com/KILTprotocol/sdk-js/tree/aa/dip-merkle-proof).
  • Loading branch information
ntn-x2 committed Apr 17, 2023
1 parent 424f022 commit 88fe5b0
Show file tree
Hide file tree
Showing 29 changed files with 1,052 additions and 115 deletions.
24 changes: 23 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ dip-sender-runtime-template = {path = "dip-template/runtimes/dip-sender", defaul

# Internal runtime API (with default disabled)
kilt-runtime-api-did = {path = "runtime-api/did", default-features = false}
kilt-runtime-api-dip-sender = {path = "runtime-api/dip-sender", default-features = false}
kilt-runtime-api-public-credentials = {path = "runtime-api/public-credentials", default-features = false}
kilt-runtime-api-staking = {path = "runtime-api/staking", default-features = false}

Expand Down Expand Up @@ -136,6 +137,7 @@ sp-session = {git = "https://github.com/paritytech/substrate", default-features
sp-staking = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"}
sp-std = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"}
sp-transaction-pool = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"}
sp-trie = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"}
sp-version = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"}
sp-weights = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"}
try-runtime-cli = {git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39"}
Expand Down
24 changes: 20 additions & 4 deletions crates/dip/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub mod latest {
}

#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
#[non_exhaustive]
pub enum VersionedIdentityProofAction<Identifier, Proof, Details = ()> {
#[codec(index = 1)]
V1(v1::IdentityProofAction<Identifier, Proof, Details>),
Expand All @@ -45,13 +46,28 @@ impl<Identifier, Proof, Details> From<v1::IdentityProofAction<Identifier, Proof,
}

#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo)]
pub enum VersionedIdentityProof<LeafKey, LeafValue> {
#[non_exhaustive]
pub enum VersionedIdentityProof<BlindedValue, Leaf> {
#[codec(index = 1)]
V1(v1::Proof<LeafKey, LeafValue>),
V1(v1::Proof<BlindedValue, Leaf>),
}

impl<LeafKey, LeafValue> From<v1::Proof<LeafKey, LeafValue>> for VersionedIdentityProof<LeafKey, LeafValue> {
fn from(value: v1::Proof<LeafKey, LeafValue>) -> Self {
impl<BlindedValue, Leaf> From<v1::Proof<BlindedValue, Leaf>> for VersionedIdentityProof<BlindedValue, Leaf> {
fn from(value: v1::Proof<BlindedValue, Leaf>) -> Self {
Self::V1(value)
}
}

impl<BlindedValue, Leaf> TryFrom<VersionedIdentityProof<BlindedValue, Leaf>> for v1::Proof<BlindedValue, Leaf> {
// Proper error handling
type Error = ();

fn try_from(value: VersionedIdentityProof<BlindedValue, Leaf>) -> Result<Self, Self::Error> {
#[allow(irrefutable_let_patterns)]
if let VersionedIdentityProof::V1(v1::Proof { blinded, revealed }) = value {
Ok(Self { blinded, revealed })
} else {
Err(())
}
}
}
6 changes: 5 additions & 1 deletion crates/dip/src/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ pub enum IdentityProofAction<Identifier, Proof, Details = ()> {
}

#[derive(Encode, Decode, RuntimeDebug, Clone, Eq, PartialEq, TypeInfo, Default)]
pub struct Proof<LeafKey, LeafValue>(Vec<(LeafKey, LeafValue)>);
pub struct Proof<BlindedValue, Leaf> {
pub blinded: BlindedValue,
// TODO: Probably replace with a different data structure for better lookup capabilities
pub revealed: Vec<Leaf>,
}
3 changes: 3 additions & 0 deletions dip-template/runtimes/dip-receiver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ scale-info = {workspace = true, features = ["derive"]}
# DIP
pallet-did-lookup.workspace = true
pallet-dip-receiver.workspace = true
runtime-common.workspace = true

# Substrate
frame-executive.workspace = true
Expand Down Expand Up @@ -74,6 +75,7 @@ std = [
"scale-info/std",
"pallet-did-lookup/std",
"pallet-dip-receiver/std",
"runtime-common/std",
"frame-executive/std",
"frame-support/std",
"frame-system/std",
Expand Down Expand Up @@ -118,6 +120,7 @@ runtime-benchmarks = [
"frame-system/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"pallet-dip-receiver/runtime-benchmarks",
"runtime-common/runtime-benchmarks",
"xcm-builder/runtime-benchmarks",
"pallet-xcm/runtime-benchmarks",
]
17 changes: 7 additions & 10 deletions dip-template/runtimes/dip-receiver/src/dip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,17 @@

// If you feel like getting in touch with us, you can do so at [email protected]

use pallet_dip_receiver::traits::SuccessfulProofVerifier;
use runtime_common::dip::{receiver::DidMerkleProofVerifier, ProofLeaf};
use sp_std::vec::Vec;

use crate::{DidIdentifier, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin};
use crate::{BlockNumber, DidIdentifier, Hash, Hasher, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin};

impl pallet_dip_receiver::Config for Runtime {
type BlindedValue = Vec<Vec<u8>>;
type Identifier = DidIdentifier;
// TODO: Change with right one
type ProofDigest = [u8; 32];
// TODO: Change with right one
type ProofLeafKey = [u8; 4];
// TODO: Change with right one
type ProofLeafValue = [u8; 4];
// TODO: Change with right one
type ProofVerifier = SuccessfulProofVerifier<Self::ProofDigest, Self::ProofLeafKey, Self::ProofLeafValue>;
type ProofLeaf = ProofLeaf<Hash, BlockNumber>;
type ProofDigest = Hash;
type ProofVerifier = DidMerkleProofVerifier<Hash, BlockNumber, Hasher>;
type RuntimeCall = RuntimeCall;
type RuntimeEvent = RuntimeEvent;
type RuntimeOrigin = RuntimeOrigin;
Expand Down
15 changes: 8 additions & 7 deletions dip-template/runtimes/dip-receiver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ use sp_core::{crypto::KeyTypeId, ConstU128, ConstU16, OpaqueMetadata};
use sp_inherents::{CheckInherentsResult, InherentData};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, OpaqueKeys, Verify},
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, OpaqueKeys},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, MultiSignature, OpaqueExtrinsic,
AccountId32, ApplyExtrinsicResult, MultiSignature, OpaqueExtrinsic,
};
use sp_std::{prelude::*, time::Duration};
use sp_version::RuntimeVersion;
Expand All @@ -73,14 +73,15 @@ pub use sp_runtime::BuildStorage;
#[cfg(feature = "std")]
use sp_version::NativeVersion;

pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
pub type AccountId = AccountId32;
pub type Address = MultiAddress<AccountId, ()>;
pub type Balance = u128;
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
pub type BlockNumber = u32;
pub type DidIdentifier = AccountId;
pub type Hasher = BlakeTwo256;
pub type Hash = sp_core::H256;
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
pub type Header = generic::Header<BlockNumber, Hasher>;
pub type Index = u32;
pub type Signature = MultiSignature;

Expand Down Expand Up @@ -149,7 +150,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("dip-receiver-runtime-template"),
impl_name: create_runtime_str!("dip-receiver-runtime-template"),
authoring_version: 1,
spec_version: 1,
spec_version: 11100,
impl_version: 0,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
Expand Down Expand Up @@ -228,8 +229,8 @@ impl frame_system::Config for Runtime {
type BlockWeights = RuntimeBlockWeights;
type DbWeight = RocksDbWeight;
type Hash = Hash;
type Hashing = BlakeTwo256;
type Header = generic::Header<BlockNumber, BlakeTwo256>;
type Hashing = Hasher;
type Header = generic::Header<BlockNumber, Hasher>;
type Index = Index;
type Lookup = AccountIdLookup<AccountId, ()>;
type MaxConsumers = ConstU32<16>;
Expand Down
7 changes: 6 additions & 1 deletion dip-template/runtimes/dip-sender/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ scale-info = {workspace = true, features = ["derive"]}
# DIP
did.workspace = true
dip-support.workspace = true
kilt-runtime-api-dip-sender.workspace = true
pallet-dip-sender.workspace = true
runtime-common.workspace = true

# Substrate
frame-executive.workspace = true
Expand Down Expand Up @@ -74,7 +76,9 @@ std = [
"scale-info/std",
"did/std",
"dip-support/std",
"kilt-runtime-api-dip-sender/std",
"pallet-dip-sender/std",
"runtime-common/std",
"frame-executive/std",
"frame-support/std",
"frame-system/std",
Expand Down Expand Up @@ -115,9 +119,10 @@ std = [
]
runtime-benchmarks = [
"did/runtime-benchmarks",
"pallet-dip-sender/runtime-benchmarks",
"runtime-common/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"pallet-dip-sender/runtime-benchmarks",
"pallet-xcm/runtime-benchmarks",
"xcm-builder/runtime-benchmarks"
]
29 changes: 12 additions & 17 deletions dip-template/runtimes/dip-sender/src/dip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

// If you feel like getting in touch with us, you can do so at [email protected]

use did::did_details::DidDetails;
use dip_support::VersionedIdentityProofAction;
use pallet_dip_sender::traits::{
DefaultIdentityProofGenerator, DefaultIdentityProvider, TxBuilder, XcmRouterDispatcher,
};
use pallet_dip_sender::traits::{TxBuilder, XcmRouterDispatcher};
use parity_scale_codec::{Decode, Encode};
use runtime_common::dip::sender::{DidIdentityProvider, DidMerkleRootGenerator};
use xcm::{latest::MultiLocation, DoubleEncoded};

use crate::{DidIdentifier, Runtime, RuntimeEvent, XcmRouter};
use crate::{DidIdentifier, Hash, Runtime, RuntimeEvent, XcmRouter};

#[derive(Encode, Decode)]
enum ReceiverParachainCalls {
Expand All @@ -34,16 +34,16 @@ enum ReceiverParachainCalls {
#[derive(Encode, Decode)]
enum ReceiverParachainDipReceiverCalls {
#[codec(index = 0)]
ProcessIdentityAction(VersionedIdentityProofAction<DidIdentifier, [u8; 32]>),
ProcessIdentityAction(VersionedIdentityProofAction<DidIdentifier, Hash>),
}

pub struct ReceiverParachainTxBuilder;
impl TxBuilder<DidIdentifier, [u8; 32]> for ReceiverParachainTxBuilder {
impl TxBuilder<DidIdentifier, Hash> for ReceiverParachainTxBuilder {
type Error = ();

fn build(
_dest: MultiLocation,
action: VersionedIdentityProofAction<DidIdentifier, [u8; 32]>,
action: VersionedIdentityProofAction<DidIdentifier, Hash>,
) -> Result<DoubleEncoded<()>, Self::Error> {
let double_encoded: DoubleEncoded<()> =
ReceiverParachainCalls::DipReceiver(ReceiverParachainDipReceiverCalls::ProcessIdentityAction(action))
Expand All @@ -55,16 +55,11 @@ impl TxBuilder<DidIdentifier, [u8; 32]> for ReceiverParachainTxBuilder {

impl pallet_dip_sender::Config for Runtime {
type Identifier = DidIdentifier;
// TODO: Change with right one
type Identity = u32;
// TODO: Change with right one
type IdentityProofDispatcher = XcmRouterDispatcher<XcmRouter, DidIdentifier, [u8; 32]>;
// TODO: Change with right one
type IdentityProofGenerator = DefaultIdentityProofGenerator;
// TODO: Change with right one
type IdentityProvider = DefaultIdentityProvider;
// TODO: Change with right one
type ProofOutput = [u8; 32];
type Identity = DidDetails<Runtime>;
type IdentityProofDispatcher = XcmRouterDispatcher<XcmRouter, DidIdentifier, Hash>;
type IdentityProofGenerator = DidMerkleRootGenerator<Runtime>;
type IdentityProvider = DidIdentityProvider<Runtime>;
type ProofOutput = Hash;
type RuntimeEvent = RuntimeEvent;
type TxBuilder = ReceiverParachainTxBuilder;
}
Loading

0 comments on commit 88fe5b0

Please sign in to comment.