SpruceKit
SpruceID
  • 🌲SpruceKit Introduction
    • Decentralized Identity Overview
    • Glossary
  • ⚡Quickstart
  • SpruceKit Mobile
    • SpruceKit Showcase App
      • Installation
      • Getting Started
      • Issue a Showcase Credential
      • Present a Showcase Credential
    • SpruceKit Mobile SDK
      • Introduction
      • Core Components
        • StorageManager
        • KeyManager
        • CredentialPack
        • Card
        • IsoMdlPresentation
        • mDocReader/IsomDLReader
        • Document Scanner
      • SpruceKit iOS SDK
        • Installation
        • Build a Wallet
          • Accept a W3C VC
          • Present a W3C VC
          • Present mDL in-person/offline
          • Present an mDL over the internet
        • Build a Verifier
          • Verify a W3C VC
          • Verify an mDL in-person/offline
          • Verify an mDL over the internet
      • SpruceKit Android SDK
        • Installation
        • Build a Wallet
          • Accept a W3C VC
          • Present a W3C VC
          • Present an mDL in-person/offline
          • Present an mDL over the internet
        • Build a Verifier
          • Verify a W3C VC
          • Verify an mDL in-person/offline
          • Verify an mDL over the internet
  • Verifiable Digital Credentials
    • ⚙️DIDKit
      • Installation
      • Core Concepts
      • DID Methods
      • Runtime Configuration
      • Specifications and Dependencies
      • Quickstart
      • DIDKit Packages
        • Command Line Interface
        • HTTP Server
        • Rust Crate
        • C Interface
        • Java and Android
        • Python
        • Javascript
      • DIDKit Examples
        • Core Functions (CLI)
        • Core Functions (HTTP)
        • did-web in minutes
        • Batch Generation & Verification
    • 🪪ISO mDL
      • Quickstart
      • Core Concepts
      • User Guide
  • Schema Definition Language
    • 🔗TreeLDR
      • TreeLDR Quickstart
        • First Schema
        • Compilation into JSON Schema
        • Compilation into JSON-LD Context
        • Writing a Layout
        • Simple Rust Integration
      • Types
        • Literal Types
      • Layouts
        • Primitive Layouts
        • Literal Layouts
        • Enumeration
        • Array Layout
        • References
      • Compiling
        • Schema Definition Formats
          • JSON Schema
          • JSON-LD Context
          • Resource Description Framework (RDF)
        • Programming Languages
          • Compiling to Rust
      • RDF Vocabulary
      • 💡TreeLDR Basics
        • Types and Layouts
        • Properties
        • Syntax
  • Witness for Credential Claims
    • 🔭Rebase
      • Core Library
      • Rust Client/Witness SDK
      • WASM Client SDK
      • Simple "Basic Post" Schema
      • DNS Witness Flow Schema
  • References
    • Contributing
    • Code of Conduct
Powered by GitBook
On this page
  • Project Creation
  • Credential Definition in TreeLDR
  • Credential Definition in TreeLDR
  • Rebase's SchemaType Trait Implementation

Was this helpful?

  1. Witness for Credential Claims
  2. Rebase

DNS Witness Flow Schema

This example shows how to create a Rust application with rebase that uses TreeLDR to define a simple DNS witness flow VC. The program will consist of:

  • a TreeLDR schema defining the credential type,

  • an implementation of Rebase's SchemaType trait for the credential schema.

Project Creation

First, create a new Rust project using cargo:

cargo new dns-example
cd dns-example

The src directory will contain the sources of our application. For now, it only contains a main.rs file with a dummy main function definition.

Credential Definition in TreeLDR

Create a new src/dns.tldr file that will contain the VC definition:

base <https://example.com/>;
use <http://www.w3.org/2000/01/rdf-schema#> as rdfs;
use <http://www.w3.org/2001/XMLSchema#> as xs;
use <https://treeldr.org/> as tldr;
use <https://www.w3.org/2018/credentials#> as vc;

/// DNS Verification Message.
type DnsVerificationMessage {
	// Include the type inside the layout as `@type`.
	// This will force TreeLDR to generate a type scoped context
	// for `DnsVerificationMessage` when generating the
	// JSON-LD context.
	rdf:type as @type: required multiple &rdfs:Class,

	timestamp: required xs:dateTime,
	dnsServer: required xs:string
}

/// DNS Verification Subject.
layout DnsVerificationSubject for rdfs:Resource {
	tldr:self as id: required &rdfs:Resource,

	schema:sameAs: &rdfs:Resource
}

/// DNS Verification VC.
type DnsVerification =
	vc:VerifiableCredential &
	all vc:credentialSubject: (rdfs:Resource with DnsVerificationSubject) &
	all vc:evidence: DnsVerificationMessage;

The DnsVerification type is a vc:VerifiableCredential where the credential subject is any resource represented with the DnsVerificationSubject layout, and evidences are any DnsVerificationMessage.

curl https://raw.githubusercontent.com/spruceid/treeldr/main/examples/vc.tldr > src/vc.tldr

Credential Definition in TreeLDR

treeldr-rust-macros = { git = "https://github.com/spruceid/treeldr.git" }
treeldr-rust-prelude = { git = "https://github.com/spruceid/treeldr.git" }

Then add the following module definition annotated with the #[tldr] procedural macro attribute to the src/main.rs file:

#[tldr(
	"src/dns.tldr"
)]
mod schema {
	#[prefix("http://www.w3.org/2001/XMLSchema#")]
	pub mod xs {}
	
	#[prefix("https://www.w3.org/2018/credentials#")]
	pub mod vc {}

	#[prefix("https://example.com/")]
	pub mod example {}
}

At compile time, this macro call will expand to add the following two type definitions in the schema::example module:

pub struct DnsVerificationMessage {
	type_: BTreeSet<treeldr_rust_prelude::Id>,
	timestamp: super::xs::DateTime,
	dns_server: super::xs::String
}

pub struct DnsVerificationSubject {
	id: treeldr_rust_prelude::Id,
	same_as: Option<treeldr_rust_prelude::Id>
}

Rebase's SchemaType Trait Implementation

use ssi::{one_or_many::OneOrMany, vc::Evidence};
use rebase::schema::schema_type::{SchemaError, SchemaType};
use rebase::signer::signer::DID as SignerDID;

pub struct Schema {
	pub domain: String,
	pub key_type: SignerDID,
}

impl SchemaType for Schema {
	fn context(&self) -> Result<serde_json::Value, SchemaError> {
		todo!()
	}

	fn subject(&self) -> Result<serde_json::Value, SchemaError> {
		todo!()
	}

	fn evidence(&self) -> Result<Option<OneOrMany<Evidence>>, SchemaError> {
		todo!()
	}

	fn types(&self) -> Result<Vec<String>, SchemaError> {
		Ok(vec![
			"VerifiableCredential".to_string(),
			"DnsVerification".to_string(),
		])
	}
}

We now need to fill-in the blanks for the context, subject and evidence methods.

context Implementation

We can then generate the associated JSON-LD context using the following command:

tldrc -i src/vc.tldr -i src/dns.tldr json-ld-context -c https://www.w3.org/2018/credentials/v1 https://example.com/DnsVerificationMessage

Using the output of the command, replace the todo!() in the context method with:

Ok(serde_json::json!([
	"https://www.w3.org/2018/credentials/v1",
	{
		"sameAs": "http://schema.org/sameAs",
		"DnsVerification": "https://example.com/DnsVerification",
		"DnsVerificationMessage": {
			"@id": "https://example.com/DnsVerificationMessage",
			"@context": {
				"timestamp": {
					"@id": "https://example.com/timestamp",
					"@type": "http://www.w3.org/2001/XMLSchema#dateTime"
				},
				"dnsServer": "https://example.com/dnsServer"
			}
		}
	}
]))

subject Implementation

The subject of the VC, a DnsVerifiactionSubject, is derived from the key type. We use schema::example::DnsVerificationSubject to build the subject and convert it into a serde_json::Value. Replace the todo!() in the subject method with:

use treeldr_rust_prelude::{Id, IntoJsonLd};

let signer_type = SignerTypes::new(&self.key_type)?;
let signer_did = signer_type
	.did_id()
	.map_err(|e| SchemaError::BadSubject(e.to_string()))?;

let mut subject = schema::example::DnsVerificationSubject::new(Id::try_from(signer_did).unwrap());
subject.same_as.insert(Id::try_from(format!("dns:{}",  self.domain)).unwrap());

Ok(subject.into_json_ld().into())

evidence Implementation

The evidence is a DnsVerificationMessage, however we will not be able to use the schema::example::DnsVerificationMessage type defined by TreeLDR since rebase expect an ssi::vc::Evidence instance. Instead we will closely follow the structure of a DnsVerificationMessage to build the evidence by hand. Replace the todo!() in the evidence method with:

let mut evidence_map = HashMap::new();

evidence_map.insert(
	"timestamp".to_string(),
	serde_json::Value::String(Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true)),
);

evidence_map.insert(
	"dnsServer".to_string(),
	serde_json::Value::String("https://cloudflare-dns.com/dns-query".to_string()),
);

let evidence = Evidence {
	id: None,
	type_: vec!["DnsVerificationMessage".to_string()],
	property_set: Some(evidence_map),
};

Ok(Some(OneOrMany::One(evidence)))
PreviousSimple "Basic Post" SchemaNextContributing

Last updated 1 year ago

Was this helpful?

Instead of defining the vc:VerifiableCredential type ourselves in this file, we will rely on . In the terminal, use the following command to download this file as src/vc.tldr:

We will embed the previous schema definition into the Rust program as a type definition using the #[tldr] procedural macro attribute provided by the . This crate rely on the . First, add those two crates to the dependencies of the Rust program by adding the following lines to the Cargo.toml file under the [dependencies] section:

Contrarily to the , SchemaType will not directly be implemented for the credential subject type (here DnsVerificationMessage). Instead, we create a dedicated Schema type that will generate the credential subjects and evidence. Add the following items in the src/main.rs file:

🔭
an example file provided in the TreeLDR repository that contains VC type definitions
treeldr-rust-macros crate
treeldr-rust-prelude crate
"Basic Post" example