Implementing Data Integrity for Verifiable Credentials

Dr. Greg M. Bernstein

Introduction

Who Am I

What’s This about?

  • Credential development, issuance, verification
  • Use VC Data Model 2.0, JSON-LD 1.1 for credential design
  • Use VC Data Integrity 1.0 and Specific Cryptosuites to secure, issue and verify
  • Use appropriate DIDs for development and deployment
  • Somewhat from an applied cryptographic point of view (where are the keys!)

Beyond Test Vectors

  • All VC DI crypto suites include test vectors
  • VC-DI-EdDSA 1.0 includes eddsa-rdfc-2022 and eddsa-jcs-2022 suites and has simple and enhanced test vectors as well as test vectors for proof sets and chains.
  • VC-DI-ECDSA 1.0 includes ecdsa-rdfc-2019, ecdsa-jcs-2019, and ecdsa-sd-2023 over curves P-256 and P-384 and test vectors.

Beyond Sample Code and Sample Server

An Example Application of VCs

  • Non-governmental
  • Non-profit and as small as can be
  • Small enough for student implementation

Application: School or Community Club

A 3rd Semester of Web Development?

  1. Basic front end and back end development Introduction to full stack web development
  2. More elaborate access control, security, and validation Web Systems, Cybersecurity: An Overview
  3. Design verifiable credentials, issue and provide for their verification

Cooperating School/Community Clubs Use Case

Suppose that we have two community hiking clubs: The Arcata Tall Trees Hiking Club and the White Mountain Old Trees Hiking Club Both clubs exists to promote the “great outdoors”, hiking safety, and comraderie.

Figure 1: The tallest trees (Coast Redwoods)
Figure 2: The oldest trees (Bristlecone pine)

Clubs for Teaching Web Dev

  • Students make up their own club to build over a semester. Example: Bay Area Windsurf Foiling Club.

  • To make the club interesting from a VC perspective the club should certify knowledge, skills, or something else about a member. What they choose to certify is up to the club/student.

  • An example of a real club is the Cal Sailing Club, a university club that morphed into a community club.

VCs for our Hiking Clubs 1

  • Both clubs keep track of their active members.
  • Both clubs track members hiking knowledge and skills
  • Both clubs track members hiking accomplishments
  • Both sponsor a number of different hikes of different difficulty levels which require certain knowledge, skills, and accomplishments in order to register.

VCs for our Hiking Clubs 2

  • Clubs would like to allow members to register for some of each others hikes if prerequisites are meet.
  • To preserve members privacy clubs do NOT share their member information with each other
  • Instead clubs will issue verifiable credentials to their members so members can share this certified information as they desire

Designing the Club’s VCs

How Many Credentials

Consider a wind sport club. It might offer activities in a number of disciplines: (a) dinghy sailing, (b) keel boat sailing, (c) windsurfing, (d) windsurf foiling, (e) wing foiling.

We could have a separate credential for each discipline. Some disciplines may overlap or feed into each other (windsurfing -> windsurf foiling).

Wind Sport Club Categories

  1. General Knowledge: Dock etiquette, Tides and Currents, Wind conditions, Boundaries for skill levels.
  2. Sport and Equipment Specific Knowledge: how to assemble and attach a foil
  3. Sport Specific Skills: tacking, jibing, getting on foil
  4. Sport Specific Achievements: round XYZ buoy and returning

Things to Omit from a VC

Now there are also a number of things a club might need to know about you that do not need to be in a verifiable credential such as (a) your phone number, (b) your address, (c) your emergency contact information, (d) student status, etc…

Starting Credential (VC DM 2.0)

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://www.mysailclub.org/ns/credentials" // Our context will go here
  ],
  "id": "http://university.example/credentials/58473", // optional, id of the VC
  "name": "The name of this credential", // optional
  "description": "A description of the credential", // optional
  "type": ["VerifiableCredential", "WaterClubCredential"], // required
  "issuer": { // required, Specify the issuer nicely
    "id": "https://mysailclub.org", // club IRI (but also URL)
    "name": "My Wind Sports Club", // issuer name
    "description": "A public or school based wind sports club." // optional issuer desc
  },
  "validFrom": "2010-01-01T00:00:00Z", // optional
  "validUntil": "2020-01-01T19:23:24Z", // optional
  "credentialSubject": { // required
    "id": "did:example:ebfeb1f712ebc6f1c276e12ec21", // optional, id of the subject
    // Here is where all the custom stuff will go
  }
}

Why JSON?

  • JSON: “JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate.”
  • JSON is the text based, data “lingua franca” for the web
  • I would teach this early (week 4) in a first web programming class for CS majors. See JSON Slides

Sport Specific Credential Example

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://bawfc.grotto-networking.com/cred/foilcontext1"],
  "name": "Bay Area Windsurf Foiling Credential",
  "description": "Denotes membership, knowledge, and skills in windsurf foiling",
  "type": ["VerifiableCredential", "WindFoilCredential"],
  "issuer": {
    "id": "https://bawfc.grotto-networking.com",
    "name": "Bay Area Windsurf Foiling Club",
    "description": "Not a real club, but real information!"
  },
  "credentialSubject": {
    "type": ["Member", "WindsurfFoiler"],
    "membership": {"start": "2025-03-01T00:00:00Z", "end": "2025-10-31T00:00:00Z"},
    "knowledge": [
        {"topic": "DockEtiquette", "date": "1984-01-01T00:00:00Z"},
        {"topic": "TidesAndCurrents", "date": "2010-01-01T00:00:00Z"},
        {"topic": "WindPatterns", "date": "2010-01-01T00:00:00Z"},
        {"topic": "LandMarksBuoys","date": "2010-01-01T00:00:00Z"},
        {"topic": "BigBoatsFerries", "date": "2010-01-01T00:00:00Z"}],
    "skills": [
        {"skill": "Rigging", "date": "2010-01-01T00:00:00Z"},
        {"skill": "FoilSetup", "date": "2017-01-01T00:00:00Z"}],
    "distanceAchievements": [
        {"landmark": "TI", "date": "2010-01-01T00:00:00Z"},
        {"landmark": "R2", "date": "2011-01-01T00:00:00Z"}]
  }
}

Credential Data Validation (not Verification)

JSON is great for modeling almost any data structure imaginable. However most applications only wants certain types of data in a particular format, i.e., a small subset of possible JSON structures and content. Typically the structure and type of data is specified by a schema of some kind.

JSON-Schema 1

From JSON-Schema

  • While JSON is probably the most popular format for exchanging data, JSON Schema is the vocabulary that enables JSON data consistency, validity, and interoperability at scale.
  • JSON Schema is a declarative language for annotating and validating JSON documents’ structure, constraints, and data types

JSON-Schema 2

JSON-Schema Example for a VC

{
     "$id": "https://grotto-networking.com/simple-credential.schema.json",
     "title": "UnsignedCredential",
     "description": "A basic credential validator, data model v1.1 or v2.0",
     "type": "object",
     "properties": {
          "@context": {
               "type": "array",
               "items": {"type": ["string", "object"]}
          },
          "id": {"type": "string", "format": "uri"},
          "type": {"type": ["string", "array"]},
          "credentialSubject": {"type": ["object", "array"]},
          "issuer": {
               "anyOf": [{"type": "string", "format": "uri"},
                    {"type": "object",
                      "properties": {
                              "id": {"type": "string", "format": "uri"}
                      },
                      "required": ["id"]}
               ]
          },
          "credentialStatus": {
               "type": "object",
               "properties": {
                    "id": {"type": "string", "format": "uri"},
                    "type": {"type": ["string", "array"]
                    }},
               "required": ["type"]
          }
     },
     "required": ["@context", "type", "credentialSubject", "issuer"]
}

Using JSON-Schema 1

To actually perform checks of JSON document against a JSON-Schema, optimized code libraries are used. I use and would have my students use npm: AJV.

Using JSON-Schema 2

AJV NPM page

But What Does the Credential Mean 1?

What do the date fields mean in the credential? What do the distanceAchievements mean?

  "credentialSubject": {
    "type": ["Member", "WindsurfFoiler"],
    "membership": {"start": "2025-03-01T00:00:00Z", "end": "2025-10-31T00:00:00Z"},
    "knowledge": [
        {"topic": "DockEtiquette", "date": "1984-01-01T00:00:00Z"},
        {"topic": "TidesAndCurrents", "date": "2010-01-01T00:00:00Z"},
        {"topic": "WindPatterns", "date": "2010-01-01T00:00:00Z"},
        {"topic": "LandMarksBuoys","date": "2010-01-01T00:00:00Z"},
        {"topic": "BigBoatsFerries", "date": "2010-01-01T00:00:00Z"}],
    "skills": [
        {"skill": "Rigging", "date": "2010-01-01T00:00:00Z"},
        {"skill": "FoilSetup", "date": "2017-01-01T00:00:00Z"}],
    "distanceAchievements": [
        {"landmark": "TI", "date": "2010-01-01T00:00:00Z"},
        {"landmark": "R2", "date": "2011-01-01T00:00:00Z"}]
  }

But What Does the Credential Mean 2? Distance

Distances relative to Berkeley

Need to tell the Context of the Club

  • Berkeley based club. Distances relative to Berkeley!
  • What are those landmark abbreviations
  • What do those different date sub-fields mean

Use Global Term Definitions or Define Them

  • Use terms from published vocabularies such as Schema.org. Example: https://schema.org/givenName for givenName.
  • Uniquely define your own terms such as: “https://bawfc.grotto-networking.com/cred#distanceAchievements” for the short term: distanceAchievements
  • Assemble all the term definition into a JSON-LD @context document
  • Given human readable information about each term you define in an accompanying vocabulary document.

Example publicKeyMultibase

Club Context

{
  "@context": {
    "@protected": true,
    "Member": {
      "@id": "https://bawfc.grotto-networking.com/cred/vocab#Member",
      "@context": {
        "@protected": true,
        "membership": {
          "@id": "https://bawfc.grotto-networking.com/cred/vocab#membership",
          "@context": {
            "@protected": true,
            "start": {
              "@id": "https://bawfc.grotto-networking.com/cred/vocab#start",
              "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
            },
            "end": {
              "@id": "https://bawfc.grotto-networking.com/cred/vocab#end",
              "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
            }
          }
        }
      }
    },
    "WindsurfFoiler": {
      "@id": "https://bawfc.grotto-networking.com/cred/vocab#WindsurfFoiler",
      "@context": [
        {
          "knowledge": {
            "@id": "https://bawfc.grotto-networking.com/cred/vocab#knowledge",
            "@container": "@set",
            "@context": {
              "@protected": true,
              "topic": "https://bawfc.grotto-networking.com/cred/vocab#topic",
              "date": {
                "@id": "https://bawfc.grotto-networking.com/cred/vocab#date",
                "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
              }
            }
          }
        },
        {
          "skills": {
            "@id": "https://bawfc.grotto-networking.com/cred/vocab#skills",
            "@container": "@set",
            "@context": {
              "@protected": true,
              "skill": "https://bawfc.grotto-networking.com/cred/vocab#skill",
              "date": {
                "@id": "https://bawfc.grotto-networking.com/cred/vocab#date",
                "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
              }
            }
          }
        },
        {
          "distanceAchiements": {
            "@id": "https://bawfc.grotto-networking.com/cred/vocab#distanceAchievements",
            "@container": "@set",
            "@context": {
              "@protected": true,
              "landmark": "https://bawfc.grotto-networking.com/cred/vocab#landmark",
              "date": {
                "@id": "https://bawfc.grotto-networking.com/cred/vocab#date",
                "@type": "http://www.w3.org/2001/XMLSchema#dateTime"
              }
            }
          }
        }
      ]
    }
  }
}

This seems familiar…

Deploy Context and Vocabulary

Partial Vocabulary Markdown for Club

# WindsurfFoiler 

This **type** information more specific to the discipline of windsurf foiling which can be considered a sub-discipline of windsurfing, which can be considered a sub-discipline of sailing.

## knowledge 

*knowledge* is a set of understandings about various *topics*.

### topic 

A *topic* is a single string identitying a particular area of knowledge. Currently defined topic strings include:

* **DockEtiquette**: Be polite and don't leave your gear on the dock for any longer than necessary. Know hazards of gear and equipment around other dock users.
* **TidesAndCurrents**: We don't like to run around or get stuck in the mud. Know the advantages and disadvantages of "flood" and "ebb" tides.
* **WindPatterns**: Know the common wind directions and patterns. Know what a "fade" is. Know what "banding" is and why its not a good thing. Never go out in easterlies!
* **LandMarksBuoys**: Know the common landmarks and buoys so you can communicate effectively with your fellow sailors.
* **BigBoatsFerries**: Let's stay alive people! Know the "big boat" traffic lanes in the bay. Know that they cannot stop (well yes, they can in a mile or two!). Know the fast ferry routes and why you always need to pay attention when crossing (yes, they are really fast).

### knowledgeDate

When was this knowledge *last* demonstrated, i.e., tested.

Cryptosuites and Keys

VC-DI Cryptosuites

NIST and Digital Signatures

How to Choose the Cryptosuite 1

  • No other requirements: Choose EdDSA based signatures, more modern, faster, more rigorous foundation.
  • Older hardware requirements: You may have to use ECDSA.
  • Selective Disclosure: use either “bbs-2023” or “ecdsa-sd-2023”

How to Choose the Cryptosuite 2

Canonicalization choice?

  • Selective disclosure only works with RDFC so no choice if you want SD.
  • For our club we developed a complete @context and RDFC takes full advantage of that.
  • However JCS works fine with “regular” EdDSA and ECDSA
  • For our club we choose “eddsa-rdfc-2022”

Working with Keys

Key Recommendations and Guidelines

Types of Cryptographic Keys

NIST SP 800-57 lists 19 different types of cryptographic keys. For issuing credentials for out club we will only be concerned with their first two types:

  1. Private signature keys are the private keys of asymmetric-key (public-key) key pairs that are used by public-key algorithms to generate digital signatures intended for long-term use…
  2. A public signature-verification key is the public key of an asymmetric-key (public-key) key pair that is used by a public-key algorithm to verify digital signatures that are intended to provide source authentication and integrity authentication as well as support the non-repudiation of messages, documents, or stored data.

Generating Key Pairs

A digital signature algorithm, such as EdDSA, will provide function (or two) for generating the private and public portions of the key pair. This can be as simple as shown below.

// Key pair generation for EdDSA with the noble/curves library
import {ed25519} from '@noble/curves/ed25519.js';
let { privateKey, publicKey } = ed25519.keygen();

Representing Key Pairs

You may see a number of different formats for the same key information.

{
    // Hex representation typical used in signature spec.
    privateKeyHex: "4b49e4ec275c7590d39672508b2717c2dc1dc015e50a5d064732742413c810e0",
    publicKeyHex: "419d02f127a4703ee3e09d071a1ddf2bd8be891558c5023e64232dc7f255eda4",
    // Multibase used in lots of higher level specifications
    publicKeyMultibase: "z6MkisPQbQ4toWkXzY5C1Da76Ghc64DVe5ZU7DkMDjRtvqNj",
    privateKeyMultibase: "z3u2WHhiUqnajJreS8TQw2M57nMfjr7pD7pbme2M66U6BBgb",
    // did:key used in test vectors and interop testing
    didKey: "did:key:z6MkisPQbQ4toWkXzY5C1Da76Ghc64DVe5ZU7DkMDjRtvqNj"
}

Signature Security 1

From VC-DI-EdDSA types of signature security

  • EUF-CMA (existential unforgeability under chosen message attacks)
  • SUF-CMA (strong unforgeability under chosen message attacks)
  • Binding signature (BS)
  • Strongly Binding signature (SBS)

Signature Security 2

EUF-CMA (existential unforgeability under chosen message attacks) is usually the minimal security property required of a signature scheme. It guarantees that any efficient adversary who has the public key \(pk\) of the signer and received an arbitrary number of signatures on messages of its choice (in an adaptive manner): \(\{m_i, \sigma_i\}_{i=1}^N\), cannot output a valid signature \(\sigma^∗\) for a new message \(m^∗ \notin \{m_i\}_{i=1}^N\) (except with negligible probability). In case the attacker outputs a valid signature on a new message: \((m^∗, \sigma^∗)\), it is called an existential forgery.

Attacker Focus

  • Not on “breaking” the signature algorithm
  • Stealing private key
  • Swapping out the issuer’s public key with an imposter’s public key (where the imposter has the private key part)
  • Somehow restricting the generated private key to a smaller domain of values so that brute force approaches become viable.

Protecting Private Key Portion

  • The private portion of the key must be protected and never revealed!
  • It only needs to be known to our code that will actually run the signing algorithm.
  • Every website using HTTPS uses a private/public key pair and protects its private key!

Distributing the Public Key Portion

The public portion needs to be distributed in a way so that a verifier will have a high assurance that the public key is actually for our club and not an imposter.

Sharing Public keys with DIDs

References:

did:key direct distribution and testing

With the did:key DID method the value of key is embedded in the DID method, e.g., did:key:z6MkisPQbQ4toWkXzY5C1Da76Ghc64DVe5ZU7DkMDjRtvqNj contains an encoded verion of the actual public key value.

did:key example use

Test vector from VC-DI-EdDSA

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://www.w3.org/ns/credentials/examples/v2"
  ],
  "id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
  "type": [
    "VerifiableCredential",
    "AlumniCredential"
  ],
  "name": "Alumni Credential",
  "description": "A minimum viable example of an Alumni Credential.",
  "issuer": "https://vc.example/issuers/5678",
  "validFrom": "2023-01-01T00:00:00Z",
  "credentialSubject": {
    "id": "did:example:abcdefgh",
    "alumniOf": "The School of Examples"
  },
  "proof": {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-rdfc-2022",
    "created": "2023-02-24T23:36:38Z",
    "verificationMethod": "did:key:z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2#z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2",
    "proofPurpose": "assertionMethod",
    "proofValue": "z2YwC8z3ap7yx1nZYCg4L3j3ApHsF8kgPdSb5xoS1VR7vPG3F561B52hYnQF9iseabecm3ijx4K1FBTQsCZahKZme"
  }
}

Club Website

In previous courses the students would have

  • Developed the club website first as a static site
  • Developed a server based site with varying access privledges based on role (guest, member, admin)
  • Provided secure login/access to that site over HTTPS

Club Website and PKI

BAWFC Certification

did:web since we have HTTPS

  • The point of a DID method such as did:web is to resolve to a DID document.
  • The DID document will contain the public key information
  • It is the responsibility of the DID method to ensure authenticity, i.e., the DID document is actually under the control of the DID.

Example Club DID document

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/multikey/v1"
  ],
  "id": "did:web:bawfc.grotto-networking.com:signpubkey",
  "assertionMethod": [
    {
      "id": "did:web:bawfc.grotto-networking.com:signpubkey#vm",
      "type": "Multikey",
      "controller": "did:web:bawfc.grotto-networking.com:signpubkey",
      "publicKeyMultibase": "z6MkssZC7JGm9aBNsB5VbAWpHAcD3MNFi2anUbNY65g8vXAB"
    }
  ]
}

Resolving with did:web

  • If our DID is did:web:bawfc.grotto-networking.com:signpubkey then the above DID document would be obtain by getting the page: https://bawfc.grotto-networking.com/signpubkey/did.json.

  • Note that in the resolved URL for the DID document that https is used. This implies that the full power of HTTPS guarantees the authenticity of the DID document as comming from our club’s website.

Issuing and Verifying the VC

Adding a proof

What’s in a proof

Annotated fields based on VC Data Integrity 1.0

{
  "proof": {
    "id": "whatever...", // Optional
    "type": "DataIntegrityProof", // Required and this value only
    "proofPurpose": "assertionMethod", // Required, use this value for a VC
    // verificationMethod should "point" to the public key for the signature
    "verificationMethod": "https://di.example/issuer#z6MkjLrk3gKS2nnkeWcmcxiZPGskmesDpuwRBorgHxUXfxnG",
    "cryptosuite": "eddsa-rdfc-2022", // Required, choose as appropriate
    "created": "2023-03-05T19:23:24Z", // Optional
    "expires": "2026-03-05T19:23:24Z", // Optional
    "domain": "somekind of string", // Optional
    "challenge": "string that SHOULD be included if a domain is specified", // Optional
    "proofValue": "encoded cryptographic stuff", // Computed by cryptosuite!!!
    "previousProof": "id of another proof", // Optional, sets and chains
    "nonce": "string thingy" // Optional
  }
}

Proof Metadata/Options

  • All fields in the proof object except proofValue can be considered either proof metadata or proof options.
  • These values are cryptographically protected by the cryptosuite, i.e., are inputs to the cryptosuite as well as the unsigned credential.
  • The proofValue is an encoding of the output of the underlying signature algorithm applied to both the unsigned credential and proof options.

Inputs for Club VC Issuance

  • Unsigned club credential document (unsigned credential)
  • Club specific context document
  • Proof Options (includes verificationMethod)
  • Private key

Example Proof Options for Club

{
  "proof": {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-rdfc-2022",
    "verificationMethod": "did:key:z6MkfQxm1VBtUV7mAkzEkeM2xFxAb1rhZT5MaJmnkp4f8FDL#z6MkfQxm1VBtUV7mAkzEkeM2xFxAb1rhZT5MaJmnkp4f8FDL",
    "proofPurpose": "assertionMethod",
  }
}

Example Signed Club Credential

{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://bawfc.grotto-networking.com/cred/foilcontext1"
  ],
  "name": "Bay Area Windsurf Foiling Credential",
  "description": "Denotes membership, knowledge, and skills in windsurf foiling",
  "type": [
    "VerifiableCredential",
    "WindFoilCredential"
  ],
  "issuer": {
    "id": "https://bawfc.grotto-networking.com",
    "name": "Bay Area Windsurf Foiling Club",
    "description": "Not a real club, but real information!"
  },
  "credentialSubject": {
    "type": ["Member", "WindsurfFoiler"],
    "membership": {"start": "2025-03-01T00:00:00Z", "end": "2025-10-31T00:00:00Z"},
    "knowledge": [
      {"topic": "DockEtiquette", "date": "1984-01-01T00:00:00Z"},
      {"topic": "TidesAndCurrents", "date": "2010-01-01T00:00:00Z"},
      {"topic": "WindPatterns", "date": "2010-01-01T00:00:00Z"},
      {"topic": "LandMarksBuoys", "date": "2010-01-01T00:00:00Z"},
      {"topic": "BigBoatsFerries", "date": "2010-01-01T00:00:00Z"}
    ],
    "skills": [
      {"skill": "Rigging", "date": "2010-01-01T00:00:00Z"},
      {"skill": "FoilSetup", "date": "2017-01-01T00:00:00Z"}
    ],
    "distanceAchiements": [
      {"landmark": "TI", "date": "2010-01-01T00:00:00Z"},
      {"landmark": "R2", "date": "2011-01-01T00:00:00Z"}
    ]
  },
  "proof": {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-rdfc-2022",
    "verificationMethod": "did:key:z6MkfQxm1VBtUV7mAkzEkeM2xFxAb1rhZT5MaJmnkp4f8FDL#z6MkfQxm1VBtUV7mAkzEkeM2xFxAb1rhZT5MaJmnkp4f8FDL",
    "proofPurpose": "assertionMethod",
    "proofValue": "z6gFSUSasdoCMqqHXpHx1bsqg84qp7JEGi5GePxGkJitv3u6jqSMKQhotHpvhUwJZ2mHX3xHVYjgCW7H243RY9Ec"
  }
}

Code Files and Purposes

  • All files for this “tutorial” can be found at https://github.com/Wind4Greg/DataIntegrityTutorial
  • src/EdDSAKeyGen.js: creates private/public key pair. Puts them into multiple convenient formats in allKeys.json file; creates the did.json file with public key for did:web method.
  • src/SignCredential.js: Define proof options in here, uses `allKeys.json for private key, produces signed credential based on specified input credential.
  • scr/VerifyCredential.js: Verifies signed credential. Currently did:key verification only.
  • documentLoader.js: Loads up local versions of VC DM 2.0 context and our club context.

Libraries Used

  • @noble/curves”: For EdDSA signing and verification
  • @noble/hashes”: For SHA256 and some nice utilities
  • “jsonld”: For JSON-LD processing
  • “multiformats”: For coding and decoding key formats from/to raw bytes