Credentials

The Credentials SDK offers developers a way to manage the life-cycle of credentials including creation, proving and verification. The SDK also enables the storage of credentials using the Files SDK. The list of credentials is ONLY visible to the Wallet owner and is used for storage purposes only.

Note: The length of each entry in the Credential is constrained by a maximum of 32 characters

  1. Import the necessary libraries:

import { NotVault, Files, Credentials } from '@notcentralised/notvault-sdk';
  1. Instantiating the NotVault classes:

const vault = new NotVault();
const files = new Files(vault);
const credentials = new Credentials(vault, files);

With these statements, we instantiate the NotVault, Files, and Credentials classes, providing the necessary foundations for credential operations.

  1. Defining a dataset:

Here, we define a dataset that will be verified to create a credential. The example below describes a passport dataset.

const passport_dataset : any = {
    id: 100,
    first_name: 'Pablo',
    last_name: 'Erchanfrit',
    dob: Math.floor(new Date('1990-08-10').getTime() / 1000), // unix format
    country: 'Liechtenstein'
};
  1. Defining a schema for the credential:

We create a schema defining the structure of the credential.

const schema : Schema = {
    id: 'passport',
    type: 'alphaNumericalData',
    fields: [
        {
            id: 'id',
            name: 'Passport Number',
            type: 'number'
        },
        {
            id: 'first_name',
            name: 'First Name',
            type: 'string'
        },
        {
            id: 'last_name',
            name: 'Last Name',
            type: 'string'
        },
        {
            id: 'dob',
            name: 'Date of Birth',
            type: 'date'
        },
        {
            id: 'country',
            name: 'Country',
            type: 'string'
        }
    ]
};
  1. Issuing a credential:

Issuing a Credential is the process of creating a cryptographic dataset which is derived from an initial dataset. The Credential is an attestation of the integrity of the original dataset.

const passport_credential = await credentials.issue(
    passport_dataset, 
    schema, 
    '... Owner Public Key ...', 
    '... Signature of source credential ...',
    true // If you wish to add this credential to the wallets list of credentials using the Files SDK.
);
  1. Creating a query:

A query with constraints or criteria is necessary to generate a proof. We are proving that a Credential respects certain constraints. In the example below, we are proving that the date of birth in Credential above is between specified values. Furthermore, we are sharing an aggregated hash of the Last Name and Country fields, as this example relates to a passport.

Upper and lower boundary constraints are only applied to numbers and dates. Text data can only be verified by exact matches. Read more on this in the verification section below.

The proof will not be generated if the numerical data is not within the ranges stated in the constraints.

const query: { constraints:any, fields:any[] } = {
    constraints:{ // Upper and lower boundary constraints are only applied to numbers and dates
        dob: { lower: Math.floor(new Date('1980-08-10').getTime() / 1000), upper: Math.floor(new Date('1999-08-10').getTime() / 1000)},
    },
    fields:['last_name', 'country'] // Text data can only be verified by exact matches
};
  1. Generating a proof:

A query with constraints or criteria is necessary to generate a proof. We are proving that a Credential respects certain constraints. In the example below, we are proving that the date of birth in Credential above is between specified values. Furthermore, we are sharing an aggregated hash of the Last Name and Country fields, as this example relates to a passport.

Upper and lower boundary constraints are only applied to numbers and dates. Text data can only be verified by exact matches. Read more on this in the verification section below.

The proof will not be generated if the numerical data is not within the ranges stated in the constraints.

const proof : Proof = await credentials.prove(query, passport_dataset, schema);
  1. Verifying a credential:

Verifying a proof requires the values of the fields above. As mentioned, proofs are only generated if the numerical constraints are met. The proof will contain an aggregated hash of the text data.

The verification happens when the verifier creates an aggregated hash of the text values, which they expect the credential to contain. The first parameter below contains this information and the verification function will only return true if this information matches the information implicitly contained in the proof.

const isValid : boolean = await credentials.verify({
        last_name: 'Erchanfrit',
        country: 'Liechtenstein'
    }, 
    '... Public key of the issuer ...', 
    proof.schema, 
    proof.proof
);
  1. Listing all credentials:

We fetch all credentials.

const allCredentialsList = await credentials.list();
  1. Adding a new credential:

We add a new credential to the list.

const newCredentialsListAfterAdding : FileEntry[] = await credentials.add(
    `... any description of the dataset ...`,
    JSON.stringify(passport_dataset)
);
  1. Removing a credential:

We eliminate a credential from the private list.

const newCredentialsListAfterRemoving : FileEntry[] = await credentials.remove(`... File CID in IPFS ...`);

Please refer to the original TypeScript code context for a detailed breakdown of the parameters required for each function.

Last updated