Skip to content

Commit

Permalink
(feat) Cheqd DID resolver hyperledger#1300 (hyperledger#1305)
Browse files Browse the repository at this point in the history
* try permissions in CI

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* new crate

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* resolution working

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* check in the proto types and have a standalone generator helper (rather than generate at build time)

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* regen lock

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* cheqd did parser

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* cheqd did url tests

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* re-gen lock

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* resolver system tests are working

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* run int tests in CI

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* clippy

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* resolution with contexts

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* finish some TODOs, and add doc metadata

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* update readme

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* try bumping rust ver on vdrproxy

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* lock auto update

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* readme updates

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* remove some debugs

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* more error info

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* updated hyper in did:web. fixes clients

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* fix up tls. works on android

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

* some cleaning

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>

---------

Signed-off-by: George Mulhearn <gmulhearn@anonyome.com>
Co-authored-by: George Mulhearn <gmulhearn@anonyome.com>
  • Loading branch information
gmulhearn and gmulhearn-anonyome authored Dec 9, 2024
1 parent b84d1f9 commit 0e3bed0
Show file tree
Hide file tree
Showing 44 changed files with 4,815 additions and 61 deletions.
250 changes: 223 additions & 27 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ members = [
"misc/simple_message_relay",
"misc/display_as_json",
"did_core/did_methods/did_jwk",
"did_core/did_methods/did_cheqd",
"did_core/did_methods/did_cheqd/cheqd_proto_gen",
]

[workspace.package]
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ The repository contains Rust crates to build
- [`did_parser`](did_core/did_parser_nom) - Building and parsing [DIDs](https://w3c.github.io/did-core/)
- [`did_peer`](did_core/did_methods/did_peer) - https://identity.foundation/peer-did-method-spec/
- [`did_sov`](did_core/did_methods/did_resolver_sov) - https://sovrin-foundation.github.io/sovrin/spec/did-method-spec-template.html
- [`did_cheqd`](did_core/did_methods/did_cheqd) - https://docs.cheqd.io/product/architecture/adr-list/adr-001-cheqd-did-method
- [`did_web`](did_core/did_methods/did_resolver_web) - https://w3c-ccg.github.io/did-method-web/
- [`did_key`](did_core/did_methods/did_key) - https://w3c-ccg.github.io/did-method-key/
- [`did_jwk`](did_core/did_methods/did_jwk) - https://github.com/quartzjer/did-jwk/blob/main/spec.md
Expand Down
2 changes: 0 additions & 2 deletions aries/messages/src/msg_types/protocols/did_exchange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ mod tests {

#[test]
fn test_protocol_didexchange_v1_1() {
let x = Protocol::from(DidExchangeTypeV1::new_v1_1());
dbg!(x);
test_utils::test_serde(
Protocol::from(DidExchangeTypeV1::new_v1_1()),
json!("https://didcomm.org/didexchange/1.1"),
Expand Down
16 changes: 16 additions & 0 deletions did_core/did_doc/src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,19 @@ pub mod service;
pub mod types;
pub mod utils;
pub mod verification_method;

/// Module of commonly used DID-related JSON-LD contexts
pub mod contexts {
pub const W3C_DID_V1: &str = "https://www.w3.org/ns/did/v1";
pub const W3C_SUITE_ED25519_2020: &str = "https://w3id.org/security/suites/ed25519-2020/v1";
pub const W3C_SUITE_ED25519_2018: &str = "https://w3id.org/security/suites/ed25519-2018/v1";
pub const W3C_SUITE_JWS_2020: &str = "https://w3id.org/security/suites/jws-2020/v1";
pub const W3C_SUITE_SECP256K1_2019: &str = "https://w3id.org/security/suites/secp256k1-2019/v1";
pub const W3C_BBS_V1: &str = "https://w3id.org/security/bbs/v1";
pub const W3C_PGP_V1: &str = "https://w3id.org/pgp/v1";
pub const W3C_SUITE_X25519_2019: &str = "https://w3id.org/security/suites/x25519-2019/v1";
pub const W3C_SUITE_X25519_2020: &str = "https://w3id.org/security/suites/x25519-2020/v1";
pub const W3C_SUITE_SECP259K1_RECOVERY_2020: &str =
"https://w3id.org/security/suites/secp256k1recovery-2020/v2";
pub const W3C_MULTIKEY_V1: &str = "https://w3id.org/security/multikey/v1";
}
9 changes: 9 additions & 0 deletions did_core/did_doc/src/schema/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ pub enum OneOrList<T> {
List(Vec<T>),
}

impl<T> From<Vec<T>> for OneOrList<T> {
fn from(mut value: Vec<T>) -> Self {
match value.len() {
1 => OneOrList::One(value.remove(0)),
_ => OneOrList::List(value),
}
}
}

impl OneOrList<String> {
pub fn first(&self) -> Option<String> {
match self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,58 @@ use std::fmt::Display;
use public_key::KeyType;
use serde::{Deserialize, Serialize};

use crate::error::DidDocumentBuilderError;
use crate::{error::DidDocumentBuilderError, schema::contexts};

#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
pub enum VerificationMethodType {
/// https://w3id.org/security/suites/jws-2020/v1
JsonWebKey2020,
/// https://w3id.org/security/suites/secp256k1-2019/v1
EcdsaSecp256k1VerificationKey2019,
/// https://w3id.org/security/suites/ed25519-2018/v1
Ed25519VerificationKey2018,
/// https://w3id.org/security/suites/ed25519-2020/v1
Ed25519VerificationKey2020,
/// https://w3id.org/security/bbs/v1
Bls12381G1Key2020,
/// https://w3id.org/security/bbs/v1
Bls12381G2Key2020,
/// https://w3id.org/pgp/v1
PgpVerificationKey2021,
RsaVerificationKey2018,
/// https://w3id.org/security/suites/x25519-2019/v1
X25519KeyAgreementKey2019,
/// https://w3id.org/security/suites/x25519-2020/v1
X25519KeyAgreementKey2020,
/// https://identity.foundation/EcdsaSecp256k1RecoverySignature2020/lds-ecdsa-secp256k1-recovery2020-0.0.jsonld
EcdsaSecp256k1RecoveryMethod2020,
/// https://www.w3.org/TR/vc-data-integrity/#multikey
/// https://w3id.org/security/multikey/v1
Multikey,
}

impl VerificationMethodType {
/// Return the JSON-LD context URL for which this type comes from
pub fn context_for_type(&self) -> &str {
match self {
VerificationMethodType::JsonWebKey2020 => contexts::W3C_SUITE_JWS_2020,
VerificationMethodType::EcdsaSecp256k1VerificationKey2019 => {
contexts::W3C_SUITE_SECP256K1_2019
}
VerificationMethodType::Ed25519VerificationKey2018 => contexts::W3C_SUITE_ED25519_2018,
VerificationMethodType::Ed25519VerificationKey2020 => contexts::W3C_SUITE_ED25519_2020,
VerificationMethodType::Bls12381G1Key2020 => contexts::W3C_BBS_V1,
VerificationMethodType::Bls12381G2Key2020 => contexts::W3C_BBS_V1,
VerificationMethodType::PgpVerificationKey2021 => contexts::W3C_PGP_V1,
VerificationMethodType::X25519KeyAgreementKey2019 => contexts::W3C_SUITE_X25519_2019,
VerificationMethodType::X25519KeyAgreementKey2020 => contexts::W3C_SUITE_X25519_2020,
VerificationMethodType::EcdsaSecp256k1RecoveryMethod2020 => {
contexts::W3C_SUITE_SECP259K1_RECOVERY_2020
}
VerificationMethodType::Multikey => contexts::W3C_MULTIKEY_V1,
}
}
}

impl Display for VerificationMethodType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand All @@ -38,7 +71,6 @@ impl Display for VerificationMethodType {
VerificationMethodType::Bls12381G1Key2020 => write!(f, "Bls12381G1Key2020"),
VerificationMethodType::Bls12381G2Key2020 => write!(f, "Bls12381G2Key2020"),
VerificationMethodType::PgpVerificationKey2021 => write!(f, "PgpVerificationKey2021"),
VerificationMethodType::RsaVerificationKey2018 => write!(f, "RsaVerificationKey2018"),
VerificationMethodType::X25519KeyAgreementKey2019 => {
write!(f, "X25519KeyAgreementKey2019")
}
Expand Down
39 changes: 39 additions & 0 deletions did_core/did_methods/did_cheqd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[package]
name = "did_cheqd"
authors.workspace = true
description.workspace = true
license.workspace = true
version = "0.1.0"
edition = "2021"

[lib]
name = "did_cheqd"
path = "src/lib.rs"

[dependencies]
did_resolver = { path = "../../did_resolver" }
tonic = { version = "0.12.3", default-features = false, features = [
"codegen",
"prost",
"channel",
] }
prost = { version = "0.13.3", default-features = false }
prost-types = "0.13.3"
native-tls = { version = "0.2.12", features = ["alpn"] }
hyper-tls = "0.6.0"
hyper-util = { version = "0.1.10", features = ["client-legacy", "http2"] }
http-body-util = "0.1.2"
async-trait = "0.1.68"
serde_json = "1.0.96"
serde = { version = "1.0.160", features = ["derive"] }
thiserror = "1.0.40"
tokio = { version = "1.38.0" }
chrono = { version = "0.4.24", default-features = false }
url = { version = "2.3.1", default-features = false }
bytes = "1.8.0"

[dev-dependencies]
tokio = { version = "1.38.0", default-features = false, features = [
"macros",
"rt",
] }
14 changes: 14 additions & 0 deletions did_core/did_methods/did_cheqd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# DID Cheqd Resolver
This crate contains a resolver for DIDs of the [did:cheqd](https://docs.cheqd.io/product/architecture/adr-list/adr-001-cheqd-did-method) method. The implementation resolves DIDs via gRPC network requests to the configured nodes. Default nodes for cheqd's `mainnet` & `testnet` can be used, or custom nodes can be opt-in by supplying a different gRPC URL configuration.

The implementations in this crate are largely inspired from cheqd's own typescript [sdk](https://github.com/cheqd/sdk/blob/main/src/modules/did.ts).

This crate uses gRPC types and clients generated using [tonic](https://github.com/hyperium/tonic). The generated rust code is checked-in to this repository for monitoring, [see here](./src/proto/mod.rs). These generated rust files are checked-in alongside the V2 cheqd proto files & dependencies, [here](./cheqd_proto_gen/proto/), which are sourced from [cheqd's Buf registry](https://buf.build/cheqd/proto/docs).

Since the generated code & proto files are not relatively large nor overwhelming in content, they are checked-in rather than pulled and/or generated at build time. The benefit is that the contents of the files can be monitored with each update, making supply-chain attacks obvious. It also reduces the build time complexity for consumers - such as reducing requirements for any 3rd party build tools to be installed (`protobuf`). The drawback is that it introduces some more manual maintainence.

## Crate Maintainence
If there is an update to the `.proto` files, or `tonic` had a breaking update, the checked-in files may be due for a manual update. To do so, update any proto files in the [proto dir](./cheqd_proto_gen/proto/), then re-generate the rust files by using the [cheqd-proto-gen](./cheqd_proto_gen/) binary within this directory:
```
cargo run --bin cheqd-proto-gen
```
11 changes: 11 additions & 0 deletions did_core/did_methods/did_cheqd/cheqd_proto_gen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "cheqd_proto_gen"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "cheqd-proto-gen"
path = "src/main.rs"

[dependencies]
tonic-build = "0.12.3"
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
syntax = "proto3";

package cheqd.did.v2;

import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";

option go_package = "github.com/cheqd/cheqd-node/x/did/types";

// DidDoc defines a DID Document, as defined in the DID Core specification.
// Documentation: https://www.w3.org/TR/did-core/
message DidDoc {
// context is a list of URIs used to identify the context of the DID document.
// Default: https://www.w3.org/ns/did/v1
repeated string context = 1;

// id is the DID of the DID document.
// Format: did:cheqd:<namespace>:<unique-identifier>
string id = 2;

// controller is a list of DIDs that are allowed to control the DID document.
repeated string controller = 3;

// verificationMethod is a list of verification methods that can be used to
// verify a digital signature or cryptographic proof.
repeated VerificationMethod verification_method = 4;

// authentication is a list of verification methods that can be used to
// authenticate as the DID subject.
repeated string authentication = 5;

// assertionMethod is a list of verification methods that can be used to
// assert statements as the DID subject.
repeated string assertion_method = 6;

// capabilityInvocation is a list of verification methods that can be used to
// invoke capabilities as the DID subject.
repeated string capability_invocation = 7;

// capabilityDelegation is a list of verification methods that can be used to
// delegate capabilities as the DID subject.
repeated string capability_delegation = 8;

// keyAgreement is a list of verification methods that can be used to perform
// key agreement as the DID subject.
repeated string key_agreement = 9;

// service is a list of services that can be used to interact with the DID subject.
repeated Service service = 10;

// alsoKnownAs is a list of DIDs that are known to refer to the same DID subject.
repeated string also_known_as = 11;
}

// VerificationMethod defines a verification method, as defined in the DID Core specification.
// Documentation: https://www.w3.org/TR/did-core/#verification-methods
message VerificationMethod {
// id is the unique identifier of the verification method.
// Format: did:cheqd:<namespace>:<unique-identifier>#<key-id>
string id = 1;

// type is the type of the verification method.
// Example: Ed25519VerificationKey2020
string verification_method_type = 2 [(gogoproto.jsontag) = "type,omitempty"];

// controller is the DID of the controller of the verification method.
// Format: did:cheqd:<namespace>:<unique-identifier>
string controller = 3;

// verification_material is the public key of the verification method.
// Commonly used verification material types: publicJwk, publicKeyBase58, publicKeyMultibase
string verification_material = 4;
}

// Service defines a service, as defined in the DID Core specification.
// Documentation: https://www.w3.org/TR/did-core/#services
message Service {
// id is the unique identifier of the service.
// Format: did:cheqd:<namespace>:<unique-identifier>#<service-id>
string id = 1;

// type is the type of the service.
// Example: LinkedResource
string service_type = 2 [(gogoproto.jsontag) = "type,omitempty"];

// serviceEndpoint is the endpoint of the service.
// Example: https://example.com/endpoint
repeated string service_endpoint = 3;
}

// DidDocWithMetadata defines a DID Document with metadata, as defined in the DID Core specification.
// Contains the DID Document, as well as DID Document metadata.
message DidDocWithMetadata {
// didDocument is the DID Document.
DidDoc did_doc = 1 [(gogoproto.jsontag) = "didDocument"];

// didDocumentMetadata is the DID Document metadata.
Metadata metadata = 2 [(gogoproto.jsontag) = "didDocumentMetadata"];
}

// Metadata defines DID Document metadata, as defined in the DID Core specification.
// Documentation: https://www.w3.org/TR/did-core/#did-document-metadata-properties
message Metadata {
// created is the timestamp of the creation of the DID Document.
// Format: RFC3339
// Example: 2021-03-10T15:16:17Z
google.protobuf.Timestamp created = 1 [
(gogoproto.nullable) = false,
(gogoproto.stdtime) = true
];

// updated is the timestamp of the last update of the DID Document.
// Format: RFC3339
// Example: 2021-03-10T15:16:17Z
google.protobuf.Timestamp updated = 2 [
(gogoproto.nullable) = true,
(gogoproto.stdtime) = true
];

// deactivated is a flag that indicates whether the DID Document is deactivated.
// Default: false
bool deactivated = 3;

// version_id is the version identifier of the DID Document.
// Format: UUID
// Example: 123e4567-e89b-12d3-a456-426655440000
string version_id = 4;

// next_version_id is the version identifier of the next version of the DID Document.
// Format: UUID
// Example: 123e4567-e89b-12d3-a456-426655440000
string next_version_id = 5 [(gogoproto.nullable) = true];

// previous_version_id is the version identifier of the previous version of the DID Document.
// Format: UUID
// Example: 123e4567-e89b-12d3-a456-426655440000
string previous_version_id = 6 [(gogoproto.nullable) = true];
}
Loading

0 comments on commit 0e3bed0

Please sign in to comment.