JLINC: Data sharing under Verifiable Contractual Agreements (VCAs) with Zero-Knowledge Auditing (ZKA)

Version 9

Abstract

JLINC is a protocol for sharing data protected by an agreement on the terms under which the data is being shared.

The agreement is known as an Verifiable Contractual Agreement, or VCA, and can be a reference to a standardized agreement or a one-off specialized contract.

The base profile is HTTP-based, but any protocol that affords methods for initiating and responding to data transactions, along with metadata (headers) accompanying those interactions could be adapted.

Table of Contents

1. Introduction

1.1. Purposes of JLINC

The JLINC protocol starts with the existence of one or more Verifiable Contractual Agreements (VCAs) for a given industry or activity type. We envision these being hammered out by citizen representative groups together with industry organizations. JLINC has created a basic VCA to kick off the process.

The VCA is chosen and cryptographically signed by the initiating party and offered to the receiving party. The receiving party, if it recognizes and accepts the VCA, counter-signs it and returns it to the initiating party.

Both parties retain a copy of the signed and counter-signed VCA, and may save it to a datastore of their choice to facilitate non-repudiation.

Once the VCA signing has been completed, the parties may use the JLINC protocol to exchange information accompanied by the identifier of the VCA, indicating that the exchange is understood to be happening in the context of the VCA. Records of these exchanges (VCA events) are also retained by both parties and may also be saved accordingly.

1.2. Definitions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

2. Establishing a VCA

A completed VCA records an agreement between two parties. The heart of the VCA is the agreement itself, which may be the text of the agreement, or a URI pointing to a specific agreement instance at a VCA Terms Resource. This URI MUST be contained in the references array of the JSON-LD, and one or more references may be supplied.

The format of a VCA URI SHOULD be {scheme}{host}{versioned-filename-with-hash-of-the-agreement}.

A machine readable VCA MUST be JSON, and the format of the JSON MUST be:

{
  "version": <machine readable agreement version>,
  "references": [
    "<VCA uri>"
  ],
  "agreementId": "<UUID representing this agreement>",
  "created": <epoch time>,
  "ids": [
    "<DID id>"
  ],
  "permitted": [
    "<purpose>"
  ],
  "prohibited": [
    "<prohibition>"
  ],
  "validRoles": [
    "<role>"
  ]
}

Machine readable agreements MUST support signing via DIDs as per the [DID] W3C recommendation.

DID ids within the ids array of the agreement MAY include DID ids that the agreement originates from, and if it is included they MUST sign the agreement before it is considered valid.

The permitted array MUST contain a representation of any expressly allowed actions within the agreement content. The prohibited array MUST contain a representation of any expressly prohibited actions within the agreement content. The validRoles array MUST contain a list of roles or parties as defined within the agreement content, such as that of entity, user, and/or third-party.

3. Signing a VCA

Agreements MUST be signed utilizing a private key that represents the DIDs involved. This private key SHOULD be fully controlled by the end user, however the private key MAY be owned by an agent, if that agent was given a capability delegation from the user. Any delegation to an agent from a user MUST be cryptographically signed and provided via a DID as described below.

Signing an agreement MUST occur using an EdDSA JWT, as defined by [RFC7519], and a private key associated with any public key in the verification method of the signing DID. For example, if the signing DID document is represented by the following FedID enabled DID:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://didspec.service.info/v2/ctx.jsonld"
  ],
  "version": "2.0",
  "capabilityDelegation": [
    {
      "id": "did:service:fedid.domain.tld:GDj...",
      "type": "jlinc",
      "archiveServers": [ "https://archive.service.info" ]
    }
  ],
  "created": "2025-10-30T16:00:14Z",
  "deactivated": false,
  "id": "did:service:fedid.domain.tld:iuK...",
  "recoveryHash": "d0a634b07cea22a9e3865eb5598e0486636bb772976bf93d",
  "service": [
    {
      "id": "did:service:fedid.domain.tld:5c7...",
      "serviceEndpoint": "https://fedid.domain.tld",
      "type": "login"
    }
  ],
  "shortName": "person@fedid.domain.tld",
  "updated": "2025-10-30T16:00:14Z",
  "verificationMethod": [
    {
      "controller": "did:service:fedid.domain.tld:iuK...",
      "created": "2025-10-30T16:00:14Z",
      "deactivated": null,
      "id": "#55b72a71d2431bd5eb10b347f1b272da",
      "key": "9ud_btCMlYQRHkTyyKMNtC48avmC60fCZhWNIbOsNi0",
      "type": "device"
    }
  ],
  "proof": {
    "type":"JWS/CT",
    "created":"2023-08-08T17:59:22.907Z",
    "proofPurpose":"verification",
    "verificationMethod":"did:service:fedid.domain.tld:iuK...",
    "jws":"eyJhb..."
  }
}

Then the private key associated with the public key 9ud_btCMlYQRHkTyyKMNtC48avmC60fCZhWNIbOsNi0 should be utilized. As this DID document also contains a capability delegation that MUST be of type jlinc, any keys in the verification method array of that DID document may sign on behalf of the user.

The agreement MUST be signed via JWS following [RFC7515] after following [RFC8785] for canonicalization to deterministically sort by recursively ordering the keys alphanumerically and sorting any arrays alphanumerically. The signature must also included a signedOn value in [RFC3339] format. Signatures themselves MUST be in standard Base64 format. Signatures on agreements MUST contain a role key that identifies which role the signing DID represents from the validRoles array.

The resulting JSON data SHOULD be submitted via POST to the entity endpoint for submitting signed agreements. The format for the posted data MAY match the provided example, where the public key provided is the public key paired with the private key that was used to sign from the verification method array.

{
  "agreement": {
    "agreement": {
      "version": 1,
      "references": [
        "https://<url>/a/74d...33d"
      ],
      "agreementId": "1df77ef2-e3c6-4f2b-859d-379cb9874d78",
      "created": 1760621627589,
      "ids": [
        "did:service:fedid.domain.tld:iuK..."
      ],
      "permitted": [
        "service-analytics",
        "service-delivery"
      ],
      "prohibited": [
        "profiling",
        "third-party-analytics",
        "third-party-sharing",
        "tracking"
      ],
      "validRoles": [
        "entity",
        "third-party",
        "user"
      ]
    },
    "signature": {
      "version": 1,
      "id": "did:service:fedid.domain.tld:iuK...",
      "role": "entity"
      "signedOn": 1760621627593,
      "type": "JWS/JCS",
      "jws": "eyJ...ICg"
    }
  },
  "publicKey": "9ud_btCMlYQRHkTyyKMNtC48avmC60fCZhWNIbOsNi0"
}

Each time an agreement is signed by an individual or entity, a full, new agreement JSON record SHOULD be created with the new signature. This allows for support of multi-party signatures or many-to-one signatures such as Terms of Service.

3.1. Capability delegation for signatures

To provide the capability to one person or entity to sign an agreement on behalf of another, a capabilityDelegation MUST be used. In the above example DID, an agent represented by the DID did:service:fedid.domain.tld:GDj... (see below) is contained within the original DID document which has been proofed by a private key of the original DID. This identifies that any verificationMethod private keys from did:service:fedid.domain.tld:GDj... can be used to sign on behalf of the original DID. If an agreement is being signed, the delegated DID MUST sign using the role that the original DID would have signed with.

{
  "id": "did:service:fedid.domain.tld:GDj...",
  "type": "jlinc",
  "archiveServers": [ "https://archive.service.info" ]
}

3.2. The Nil VCA

A Nil VCA means that data exchanges are occurring without a pre-defined agreement. This MAY be used for internal systems that are leveraging auditing capabilities for data exchanges, but do not require the governance layer of an agreement.

When using a Nil VCA the agreement ID should be represented as a zeroed UUID of 00000000-0000-0000-0000-000000000000.

4. VCA events

Once a VCA has been completed, or if the parties are using a Nil VCA, the parties that are signatories to it MAY exchange data and other requests under its terms. That the exchange is taking place in the context of, and under the agreed upon rules of the VCA is indicated by including the agreement ID in the exchange, and by signing events with the keys from the same DID (or delegated DID) as the signed agreement.

Event types include the below, but MAY be substituted for types defined by the system leveraging the protocol:

Table 1
Type Description
data Covers the exchange of data

The format of the JSON MUST be:

{
  "version": <machine readable event version>,
  "eventId": "<UUID representing this event>",
  "type": "<event type>",
  "senderId": "<DID id of sender>",
  "recipientId": "<DID id of receiver>",
  "agreementId": "<UUID representing the agreement>",
  "created": <epoch time>,
  "data": <JSON or Base64 encoded object of data>
}

5. Signing an event

Once an event is created, signing SHOULD occur associated with the public key 9ud_btCMlYQRHkTyyKMNtC48avmC60fCZhWNIbOsNi0, or any key contained within the DID or delegated DIDs should be utilized.

The event MUST be signed via JWS following the same rules as agreement signing.

The resulting JSON data SHOULD be submitted via POST to the entity endpoint for submitting signed events. The format for the posted data MAY match the provided example, where the public key provided is the public key paired with the private key that was used to sign from the verification method array.

{
  "event": {
    "event": {
      "version": 1,
      "eventId": "97906fa1-e22e-4c39-bb9b-8d01decedff3",
      "type": "data",
      "senderId": "did:service:fedid.domain.tld:iuK...",
      "recipientId": "did:service:fedid.domain.tld:rE5...",
      "agreementId": "1df77ef2-e3c6-4f2b-859d-379cb9874d78",
      "created": 1760624527588,
      "data": {
        "key": "value"
      }
    },
    "signature": {
      "version": 1,
      "id": "did:service:fedid.domain.tld:iuK...",
      "signedOn": 1760624527598,
      "type": "JWS/JCS",
      "jws": "SIs...dGV"
    }
  },
  "publicKey": "9ud_btCMlYQRHkTyyKMNtC48avmC60fCZhWNIbOsNi0"
}

Each time an event is signed by an individual or entity, a full, new event JSON record SHOULD be created with the new signature.

6. Audit records

Zero-Knowledge Audit (ZKA) records SHOULD be generated for any signature event. The audit record is designed to contain no sensitive or identifiable data, allowing for a full zero-knowledge verification of data provenance and use under an agreement.

When creating an audit record, a SHA256 hash should be taken of the fully signed agreement or event record using the same canonicalization rules as signing. This hash is what is used to verify senders, receivers, data, and agreements during a retrospective auditing activity.

The format of the JSON MUST be:

{
  "version": <machine readable audit version>,
  "hashType": "SHA256",
  "digest": "<SHA256 hash of signed record>",
  "created": <epoch time>,
  "eventId|agreementId": "<UUID of the agreement or event signed>",
}

6.1. Signing an audit record

The audit record MUST be signed via JWS following the same rules as agreement signing, and MUST use the same key or keys that were used to signed the event or agreement that is a target of the audit record.

The resulting JSON data SHOULD be submitted via POST to the entity endpoint for submitting signed audits.

{
  "audit": {
    "version": 1,
    "created": 1760624529001,
    "hashType": "SHA256",
    "digest": "38f...1f8",
    "eventId": "97906fa1-e22e-4c39-bb9b-8d01decedff3",
  },
  "signature": {
    "version": 1,
    "id": "did:service:fedid.domain.tld:iuK...",
    "signedOn": 1760624527598,
    "type": "JWS/JCS",
    "jws": "lmT...YFs"
  }
}

Each time an audit record is signed by an individual or entity, a full, new audit JSON record SHOULD be created with the new signature.

7. Audit results

Audits are conducted by comparing an event or agreement record with it's corresponding audit record. The audit records can be requested from a zero-knowledge archive server, and then evaluated by the parties that control the data or participated in the event or agreement.

When running a formal audit to verify immutable events and agreements, the response MUST include the following key metrics.

7.1. Matching identifiers

This check validates if the event or agreement IDs match between the audit record and event or agreement record.

  • If the audit record contains an eventId, the compared object MUST be an event and MUST include the same eventId

  • If the audit record contains an agreementId, the compared object MUST be an agreement and MUST include the same agreementId

7.2. Valid object signature

This check validates if the signatures on the event or agreement record are valid and that the keys used to sign were valid on the DID at the time the signature was created. Checks should be conducted using standard processes detailed in [RFC7515].

7.3. Matching audit hashes

This check validates if a new hash of the signed event or agreement record matches the hash in the audit record.

  • Using the same canonicalization rules as the original audit record creation, a new SHA256 hash MUST be generated.

  • This hash MUST match the originally generated audit record hash to be considered valid.

7.4. Valid audit signatures

This check validates if the signatures on the audit record is valid. Checks should be conducted using standard processes detailed in [RFC7515].

7.5. Matching DIDs

This check validates that the DIDs used to sign the audit records are the same DIDs used to sign the original target object.

7.6. Valid event agreement

This check ensures that if the target object was an event, and an agreement exists, that the DIDs that signed the event were the included in the DIDs that signed the agreement. If the target object is the agreement, or if the target object is an event with a Nil VCA, this check always returns true.

7.7. Valid event agreement signature

This check ensures that if the target object was an event, and an agreement exists, that the signatures on the event are valid and the event occurred after the agreement was signed. If the target object is the agreement, or if the target object is an event with a Nil VCA, this check always returns true.

7.8. Returned results

The results of these audit checks MUST be returned as:

{
  "validId": <boolean>,
  "validSignature": <boolean>,
  "validAuditHash": <boolean>,
  "validAuditSignature": <boolean>,
  "validMatchingDids": <boolean>,
  "validEventAgreement": <boolean>,
  "validEventAgreementSignature": <boolean>
}

A successful pass MUST contain all values of true, such as:

{
  "validId": true,
  "validSignature": true,
  "validAuditHash": true,
  "validAuditSignature": true,
  "validMatchingDids": true,
  "validEventAgreement": true,
  "validEventAgreementSignature": true
}

Any item listed as false indicates a failure to pass the audit.

8. Compatibility with Verifiable Credentials

To enable compatibility and embedding within Verifiable Credentials ([VC]s), agreement and event JSON documents MAY be formatted as [JSONLD].

9. IANA Considerations

This memo includes no request to IANA.

10. Security Considerations

This document should not affect the security of the Internet.

11. Normative References

[DID]
W3C, "Decentralized Identifiers (DIDs) v1.0 - Core architecture, data model, and representations", , <https://www.w3.org/TR/did-1.0/>.
[JSONLD]
W3C, "JSON-LD 1.1 - A JSON-based Serialization for Linked Data", , <https://www.w3.org/TR/json-ld/>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC3339]
Klyne, G. and C. Newman, "Date and Time on the Internet: Timestamps", RFC 3339, DOI 10.17487/RFC3339, , <https://www.rfc-editor.org/rfc/rfc3339>.
[RFC7515]
Jones, M., Bradley, J., and N. Sakimura, "JSON Web Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, , <https://www.rfc-editor.org/rfc/rfc7515>.
[RFC7519]
Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token (JWT)", RFC 7519, DOI 10.17487/RFC7519, , <https://www.rfc-editor.org/rfc/rfc7519>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RFC8785]
Rundgren, A., Jordan, B., and S. Erdtman, "JSON Canonicalization Scheme (JCS)", RFC 8785, DOI 10.17487/RFC8785, , <https://www.rfc-editor.org/rfc/rfc8785>.
[VC]
W3C, "Verifiable Credentials Data Model v2.0", , <https://www.w3.org/TR/vc-data-model-2.0/>.

Authors' Addresses

Benjamin Curtis
JLINC
Victor Grey
JLINC
Jim Fournier
JLINC