Private Delegation

This tutorial follows the lifecycle of a delegated credential. It builds builds on previous turorials Issuance, Presentation, Verification and Claim Deduction.

Create a Delegation

Let's assume some root authority, did:ex:a, wants grant did:ex:b full authority to make claims on behalf of did:ex:a. To do this did:ex:a will issue a delegation credential to did:ex:b.

Boilerplate
const { v4: uuidv4 } = require('uuid');

function uuid() {
  return `uuid:${uuidv4()}`;
}

// Check out the Issuance, Presentation, Verification tutorial for info on signing
// credentials.
function signCredential(cred, issuer_secret) { ... }

// Check out the Issuance, Presentation, Verification tutorial for info on verifying
// VCDM presentations.
async function verifyPresentation(presentation) { ... }
const delegation = {
  '@context': [ 'https://www.w3.org/2018/credentials/v1' ],
  id: uuid(),
  type: [ 'VerifiableCredential' ],
  issuer: 'did:ex:a',
  credentialSubject: {
    id: 'did:ex:b',
    'https://rdf.dock.io/alpha/2021#mayClaim':
      'https://rdf.dock.io/alpha/2021#ANYCLAIM'
  },
  issuanceDate: new Date().toISOString(),
};
const signed_delegation = signCredential(delegation, dida_secret);

Next did:ex:a sends the signed credential to did:ex:b.

Issue a Credential as a Delegate

did:ex:b accepts the delegation credential from did:ex:a. Now did:ex:b can use the delegation to make arbitrary attestations on behalf of did:ex:a.

const newcred = {
  '@context': [ 'https://www.w3.org/2018/credentials/v1' ],
  id: uuid(),
  type: [ 'VerifiableCredential' ],
  issuer: 'did:ex:b',
  credentialSubject: {
    id: 'did:ex:c',
    'https://example.com/score': 100,
  },
  issuanceDate: new Date().toISOString(),
};
const signed_newcred = signCredential(newcred, didb_secret);

So far we have two credentials, signed_delegation and signed_newcred. signed_delegation proves that any claim made by did:ex:b is effectively a claim made by did:ex:a. signed_newcred proves tha did:ex:b claims that did:ex:c has a score of 100. By applying one of the logical rules provided by the sdk, we can infer that did:ex:a claims did:ex:c has a score of 100. The logical rule named MAYCLAIM_DEF_1 will work for this use-case. MAYCLAIM_DEF_1 will be used by the verifier.

Now did:ex:b has both signed credentials. did:ex:b may now pass both credentials to the holder. In this case the holder is did:ex:c. did:ex:c also happens to be the subject of one of the credentials.

Present a Delegated Credential

did:ex:c now holds two credentials, signed_delegation and signed_newcred. Together they prove that did:ex:a indirectly claims did:ex:c to have a score of 100. did:ex:c wants to prove this statement to another party, a verifier. did:ex:c must bundle the two credentials into a VCDM presentation.

let presentation = {
  '@context': [ 'https://www.w3.org/2018/credentials/v1' ],
  type: [ 'VerifiablePresentation' ],
  id: uuid(),
  holder: `did:ex:c`,
  verifiableCredential: [ signed_delegation, signed_newcred ],
};

presentation is sent to the verifier.

Accept a Delegated Credential

The verifier receives presentation, verifies the enclosed credentials, then reasons over the union of all the credentials in the bundle using the rule MAYCLAIM_DEF_1. The process is the one outlined in Verifier-Side Reasoning but using a different composite claim and a different rule list.

import { MAYCLAIM_DEF_1 } from '@docknetwork/sdk/rdf-defs';
import { proveCompositeClaims } from '../src/utils/cd';
import jsonld from 'jsonld';

const compositeClaim = [
  { Iri: 'did:ex:c' },
  { Iri: 'https://example.com/score' },
  { Literal: { datatype: 'http://www.w3.org/2001/XMLSchema#integer', value: '100' } }
  { Iri: 'did:ex:a' },
];

let ver = await verifyPresentation(presentation);
if (!ver.verified) {
  throw ver;
}

const expPres = await jsonld.expand(presentation);

try {
  await proveCompositeClaims(expPres, [compositeClaim], MAYCLAIM_DEF_1);
  console.log('the composite claim was shown to be true');
} except (e) {
  console.error('veracity of the composite claim is unknown');
}