All pages
Powered by GitBook
1 of 9

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Generate Proof

Prerequisites

Before using the Generating Proof Endpoint, There are three essential items you'll need to use the endpoint:

  1. encryptedUserDataToken : This token contains your encrypted user data

  2. encryptedDvrToken : This token holds your encrypted DVR data

  3. apiToken : This unique identifier authenticates your requests with the zkPass API

apiToken is the base64 form of YOUR_API_KEY:YOUR_API_SECRET.

Generating Encrypted Tokens:

For instructions on creating the encryptedUserDataToken and encryptedDvrToken, refer to our section. It provides a step-by-step guide that covers:

  1. : This creates the keys you'll use for signing your data.

  2. : This step adds a digital signature to your data tokens, ensuring their authenticity.

  3. : This encrypts your data tokens, making them unreadable by anyone without the decryption key.

Endpoint

Type
Value

Request Header

Parameter
Description

Request Body

Parameter
Type
Mandatory
Description

Please see example of encrypted User Data and DVR .

Response

RESTful API

This section explains how to use the zkPass service using any programming language that we don't currently support.

Utilities

This guide complements your understanding of our API endpoints by delving into key generation, signing, and encryption. These steps are crucial for securing your data tokens when using zkPass.

Key Pair Generation

This pair consists of two keys: a public key and a private key. Think of them like a lock and key combination.

  1. Public Key: This key is freely shared and used to verify the authenticity of your signed data tokens.

  2. Private Key: Keep this key safe! It's used for signing and decrypting your data tokens.

Signing for Trust: Securing Your Data Tokens

Signing your data tokens adds a digital signature using your private key. This signature acts like a tamper-proof seal, ensuring anyone receiving the token can confirm it hasn't been altered.

Encryption for Privacy: Keeping Your Data Confidential

Encryption takes your data tokens and scrambles them using your private key. This makes the data unreadable by anyone who doesn't possess the corresponding public key (which you wouldn't share).

HTTP Method

POST

API endpoint (Playground)

https://playground-zkpass.ssi.id/api/1.0/dvr/1.0/proof

Authorization

base64 form of YOUR_API_KEY:YOUR_API_SECRET

Content-Type

Indicates that the content being sent or received is JSON data

user_data_token

string

Mandatory

encrypted user data token in JWE format

dvr_token

string

Mandatory

encrypted dvr token in JWE format

Utilities
Generating a Key Pair
Signing User Data and DVR
Encrypting User Data and DVR
here
Authorization: Basic [apiToken]
Content-Type: application/json
{
    "user_data_token": "[encryptedUserDataToken]",
    "dvr_token": "[encryptedDvrToken]"
}
{
    "status": 200,
    "proof": "eyJ0e..."
}

Generate Key Pair

Overview

We are using elliptic curve cryptography (ECC) for our encryption. The key pair should be generated using P-256 curve. Ensure the generated key pair is in PEM format.

The public key should be encoded in SPKI format, and the private key should be encoded in PKCS#8 format.

Public Key Format

  1. PEM format

  2. SPKI encoding

Private Key Format

  1. PEM format

  2. PKCS#8 encoding

Example Implementation

Here's the example of generating key pair in Typescript.

Output Example

After this section you should have a key pair consisting of :

  1. publicKeyJWKS

  2. privateKey

Ideally, the issuer & verifier should have different key pairs.

Make sure you have both them before proceeding to the next section.

Here's the example for publicKeyJWKS and privateKey.

import crypto from "crypto";

interface PublicKeyJWKS {
  x: string;
  y: string;
  kid: string;
}

function generateKeyPair() {
  const keypair = crypto.generateKeyPairSync("ec", {
    namedCurve: "prime256v1",
    publicKeyEncoding: { type: "spki", format: "pem" },
    privateKeyEncoding: { type: "pkcs8", format: "pem" },
  });
  const lines: string[] = keypair.publicKey.trim().split("\n");

  const x = lines[1];
  const y = lines[2];

  const kid = "kid-for-your-key-pair";

  const publicKeyJWKS: PublicKeyJWKS = {
    x,
    y,
    kid,
  };

  const privateKey: string = keypair.privateKey;
  console.log({ publicKeyJWKS, privateKey });
  ...
}
{
  publicKeyJWKS: {
    x: 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELOmrNI4A9ML4iGJXpYlaZiYGVCxB',
    y: 'k+evjhOZEbCLj17o/ZdfEv7dUZIRKRoZ1bud5Gq8OCItDlXkTyMrtWrhdA==',
    kid: 'q6ZFSOJcTiZWJWkvUshpFw5v20xstZN/T4lt4zpKsUg='
  },
  privateKey: '-----BEGIN PRIVATE KEY-----\n' +
    'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgrSuv5exgvZGmELOL\n' +
    'RkT9fhhRxKW3SQASrTVbENIN5cKhRANCAAQs6as0jgD0wviIYleliVpmJgZULEGT\n' +
    '56+OE5kRsIuPXuj9l18S/t1RkhEpGhnVu53karw4Ii0OVeRPIyu1auF0\n' +
    '-----END PRIVATE KEY-----\n'
}

Overview

Prerequisites

Before you get started with the zkPass API, here's what you'll need:

  1. API Credentials

  2. User Data Token

  3. DVR Token

How to Access the API

The zkPass API uses a familiar approach called basic authentication to ensure secure access. Here's what you'll need:

  • API Key: This unique identifier acts like your username for the API.

  • API Secret Key: Consider this your password, but much more secure. Keep it confidential!

Register on the to obtain your API and secret keys.

Including Your Credentials:

To access the API, you'll need to provide both your API Key and API Secret Key in every request you make. They should be included in the authorization header of your requests.

Don't Have Credentials Yet?

No worries! If you haven't received your API credentials, simply fill out our easy-to-use to request them. We'll get you set up in no time.

Utilities

Our utilities section provides a detailed guide on creating a key pair. This key pair is used for signing and encrypting your user data token (and DVR token, if needed). Here's a quick overview of the steps involved:

zkPass portal
form
Generate Key Pair
Sign User Data and DVR
Encrypt User Data and DVR

Endpoints

This section provides a detailed reference for all zkPass API endpoints

Encrypt User Data and DVR

Prerequisites

Make sure you have :

  1. userDataToken

  2. dvrToken

Read section for detail info.

Overview

zkPass enhances the security of your data during transport by encrypting it before sending it over the network. The are only two entities that can access the data: the holder and zkPass host running in a Trusted Execution Environment (TEE).

Example Implementation

First, find the zkPass public key in the .well-known/jwks.json file at this endpoint: The key you're looking for has a kid (Key ID) of "ServiceEncryptionPubK".

Output Example

After this section you should have :

  1. Encrypted User Data Token (in JWE Format).

  2. Encrypted DVR Token (in JWE Format).

Here's the example

Sign User Data and DVR
https://playground-zkpass.ssi.id/.well-known/jwks.json
import { importSPKI, EncryptJWT } from "jose";

async encryptData(userDataOrDvrToken: string): Promise<string> {
    const keyUrl = 'https://playground-zkpass.ssi.id/.well-known/jwks.json';
    const fetchKeys = await fetch(keyUrl);
    const keys = await fetchKeys.json();
    const encryptionPubKey = keys.find(
      (key: { kid: string }) => key.kid === 'ServiceEncryptionPubK'
    );
    const zkPassPublicKey =
      '-----BEGIN PUBLIC KEY-----\n' +
      encryptionPubKey.x +
      '\n' +
      encryptionPubKey.y +
      '\n-----END PUBLIC KEY-----';
    const importedPublicKey = await importSPKI(zkPassPublicKey, "ES256");
    return await new EncryptJWT({ data: userDataOrDvrToken })
      .setProtectedHeader({
        alg: "ECDH-ES",
        enc: "A256GCM",
      })
      .encrypt(importedPublicKey);
  }
{
  "encryptedUserDatatoken": "eyJ0eXAiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoielJJdWp5aDdmbG84OU5MbHFweEt0VWpmckhabVd1NVIzNGNkTlhnLVMzUSIsInkiOiJwNHN6LXc3U3pGRTBMbGY2R0Z4cUd2YmtuSHpEaENHY2dMSXZvTHpIbTlZIn0sImFsZyI6IkVDREgtRVMifQ..STqfLlyIzO-vlPu-.ju8WoPSCiLBSIUNw9EzSVjINBVx5NzN_XXb4jd8GjQ8d9USaQ0i9yU2M-kXf-eD8PZDYDvQ3hvuIi25MlRlyf_vWQSIrFuReHmZxQGZE1pcg7QXYRip0u4cfUQotvGjTSsBsa_bdXvH7gAInmalzAW_KrI08yXpT-CylitTwhmlm1RdVGWvGsMlu7u6vWWFHpOgHskN50ExfAWVa5_w93euEbxOcGjgegQTGxJocfyglmXIvIlW4XhwG8sj3OotdJbHvoqFMOfjkDf27HlMgG1jvjB-Af4CpIbdp3oP0suc_aDoayYG7butqMqrgk-OPcyIC5ELyDMWErx5WzPc1DY3icRStyzG2yPbs49l2gCcnubrwVbFZu-BqIE5hB6W7A_3Vfd479Heaec_sKzFJUlj9issy4vydy2Lsp_ldaP3J5p1tYvhxDGvoCvolkGHzwfjaNlciJ1BEfwQxyeipxrkXqzQ8oSgY7q5IPe7PtZ7O7JTpwvwbT04opAQiHatnnPbdlsCECSHj1UHuBNEfXcyK7gdzo9OaYOTPcD_Gbd88Yd8DxbKVH3e3M3z7O-ipqhD9vcuw92iOF9e1q23P9MXqjWjylDxSx4xWf9-imEW8aeGDulIQQBJ8OJZv9I7_eUiBTMWxxGgmcHsLSt7Chcv6uk3qj7yoxRqf22XvnxixOw3EtaVchxglqcdsV4dIWN5ynaJb67qUv2vFyig8XvS3x2b8bHzqS0_rNQy8L6ukzK1U0ndSW3QSqi0hcQ_CEwGzKNi445IhJ-NU_a2eGI_PiLhI2M00zpVjIIkc_bGOWHaB-3yCijUS0NjDhET78KWMTmkAEDPS0JVXni3okEd4mXhskbRr6y4OH-ShANti-FE69TO5KZmKZHkuY41xPO8_XNr1sL61z-LOsWb1nVHwfClUBUvFatIy2ElkxpjAhR-FhEiwk_oq6TXwBwLHEpQ8uJ1Es8jMMz0dtZVAo6D6OoutOH5Bo8JDtXX5uJZ7sY-GQgQX1dKLozbShF5IG40uEoGE_dIrd8MHfYZ_rqFct5tobRw299rCUMS3fcLHsJj1fqZgOGlzpy6ruBUNKZPpmNGzZcUiu2zcVheUKhjr69I7LV8h5gkb4LHkx0_AK8Lxl-jgLo-C3xGDIfG0dnZ3zoLDrK0IaueQNmxX-66rlHWhSCV-pSgJpXUFd-zv-IZix_tfV3svEaHyP9tYDg7MHus9mYkyBS6IyJqtEdmsoEYHwohVCS_lL51oIragrVtNLqXDV784zyEKKNB1XwQt5jL-XdOmrsGlJgzp2gUeeEwonEX0-LniBipeuVIAsFgXJ0ThNsLzm61BSLi5wL4xcyzRh9Bws6FRjchxEPkIq8AeQZaTZOddBx1xT4-vcMtnlAAy5ON10bCULCWm-jaAdI6UGSFur106Nr14Jj1dAFIkPFq1EyLFn_2E5D1RDp3siVJ1GCmCdNeVpy3TiHnmhaCXwZ5QkO4yLru4a8s6yWtL9P4Vktcli6tFMJ68RwdJP98YzPbvtnVjlcSei7B2lorhinEGr0JRJDZVhxujvTaYLlE2bFr1UgrAH8Sr9jpViv4Y2Ux2mFKCPdJXaWPsMc1t_s1JCjavdUnskW6afK0OOquHqoMZZoBJgNPq1HXW04Crkl5dM4D6OunA6afvUqxjpzItUlveN-chXInzVv2hX3ZFl8rWyAG3U0fR9_QJJWMzKGmu.P8Ov7hrTkyYla1iTlmXptg",
  "encryptedDvrToken": "eyJ0eXAiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiSXQ0YXljSklYUUdFQWtTUjJfU3ZVRWU2QThHaGtscUkxVGxlNmR1MjFVWSIsInkiOiJNSGctcGU2RjhEUDJVbFhMZW1fd1F4NnFIVUdRS0prNzVqel96a3JnOGpjIn0sImFsZyI6IkVDREgtRVMifQ..CiVm0RozjNyk8DhZ.e2iJK7BzHqObLeB1mxO3kJo_iPZIh8H5p3nV3ZN_MtQasX2vg2jeKyGBFgklILwo9d9Sva83ZF0fOla6L9jdAUrQqXBehoWDwTLir3vjLaqITe3bsKmUIdDInmIaZHeoH3RkTn4PqPsBFDj7zFpTwCWeKBDKgZtckJ1N8gU5R-ohAnwZDzsbinGQ03x8w5UeIlmJyZcSL4MeV1NcSVSXryZIi-w_xuK3wr4JGBqSw993tArrxPfF9jENZfqrLczrYHZ08RW_CZBfjp1TxeQGM2ovlw672T-Fu_EA8giqaK4Oqi5u_a_Ixp6bHuGldtf7EeFcoSgoMP5qoK-nIkkW5mJyRqwwO0wTaYVoohfhYliTrlBdO92BW-lK9LqVjAYEG7H1LeKOmP8e2Ze42w_0BeOMlilLE6xyxSVmGZkqnTpehuIgYZmfbO-ps5pWEFXLQ5pba5tCr_jzl3-F9dGDaT3Gpvo8PM1Hn7fAKHgD6_kPaMm1e2MB8gzcfmjwBjg6M3TQ8P1alNFYgsloxCyMhiwMFx3yxKGfoDBAY-vQtaTyWT57INXFjE9DyLSm8pXxbQmA51bSt9Ke1OoTweSR1a_tBX3jMmNnrROPhS0rDQZfiCntytSuiLqIfiBv7jZOW0nH3BoUJ4DFB7j5P6inqdCl5qRRz1fz78Egij9aXuzXpD79bD6i7by8NTAJAVoXOuEPB8VFFjFA0rx3edxB3CWsGZD5lB64iGNo9WH5YdoxHW1ox6a1Vp0oHb1NYhVlxCMiLjs6R8FD7kFw-Dwl5WydUCyjO50_y_fBIAsUvTcfqS_7vCuvp-2d4WdXtBV8pdXyt-T8DCIMYObDp-X6syO7rl40L2i998euEj1cUJ4hjC9keNHRWQul6O1gIfLdZBamOpWGGQnjsHmd38lEqtxpPS0sjzPuRvjc9bg1zW0TOGslABZyt_Ura0xNr2aLFq8DTgP5F9cAKE-vSPuyhRAcj0BzgnYuxbcYblj2OPkxF5AkLmzNI4M5Bs5VVfrkN5fnlof0JuCfa7ocvCZgS01OMm-iOxeoZNlLbQz6zqPvkgfJDdsih7wwfCxkkL9m-XkGdE1_GYvaRN12EkG2gXfiYF1AxiZkdihDhU-EjHXUYnZar2TXdhjtO6zjAxDV6Iezp_O0krCXrFu95-dV_4xjexjD2vuy3QDRbsBYun9NI-nH55U_sXS8ztdPhTAG03XPMwMZmPbu1cXUZKTNIHmYA6Qr0zPwTm-BkZfZvi9dnKLEtH2LfZKGOvG6FamjarxS7-spLVrswVhbPsWugjcxfJruzaoi6XjlrMXQo5qB0yXfML5gEQEHJQHPu35C5etR8VLiUv9M7kwj-ld-7FW2M1jz6T6KktxieJseZl_YzOUdgTazSfk4zGyc8J68NQ1hIQ-uJ0GgMYvU54WOr6n_pOBKMfL_BYcNSCOFBR0YXnisFtf-r1YpfKQ3ILUmpsxS1nnTKAK8VOO1LpaItUjLrk56p-xYgdQBhnJ9jZ8xpsb7yoQqsTsug8LVn01yVyYihj2Bf6LmCsFpoDMTkN1Or491xaN0m-g4SpUPsyBPnmYvUhfUhPUw4eYXLAImWm6OxSN3cGSk3AKmt1kMRlW-ZLgAO26ecQSuYMUHhM4nJhV-aab62YEfXVB9B_nF7zPEgDS2uS7RlwIR2e-cgjzl_Lmm4pDGcvDyxp_Z7daYODMdJbwEdvE65U69K2Z_HMDLvl6Pc-jO-Y8-I5R4KMBlFuNf5i2b3RnTqRAVLwx2AJpLp55kysaGfpvH4s-9XPnRjZPjQVFIBZJtDAhJG790OsXSIxMh1nIHbyPPX7JKMVmiN_N3TeTZifEGin9IrSGPCi4z24Vn40T4MiYQEFs5vtLPoqiScm4fx9lnDUJY7F5IQn3OTU4K4XZFmm8eZkK7_gfNsylQ8aCn4GmK8X70NW4KR24eU29mt35-SCaxwYZYPopUFWo_LzyTrZug3AIqAc6AeUsU8mrK5A0rFGFboDGYHnnc-Q0Ffrnp4C64YS2E2jfe_-KfIjAwfEBigfghHhoBpX_RC5zLVoFrblJTjscgAgE6ZcVigmZPEAGMf4iQ5E8zTtrVYLlim12TEvRSNtro5wpZXgG0XuD-Qgja0V80dwfdL0QX3S_qre1d8Za43SqoZc5CEGTP98Po8GPIIpwD_006uB6qcvVVQW5BNw7KVRD48jcph3kXpGhzbkmDA5pDTfjWbbgYuFQetMdrrvGNrjr3.iLsHlasWc7GptHe5pdwD_Q"
}

Errors

The zkPass RESTful API strives to provide a smooth user experience, but occasionally errors may occur. This section equips you with knowledge about potential error responses you might encounter.

Error Response

{
    "status": [http_status_code],
    "status_code": [status_code],
    "status_text": [error_message]
}

HTTP Status Code
Status Code
Error Message
Description

Something went wrong. Contact the administrator if the error persists

Our system failed to create a new instance of the privacy app

500

CUSTOM_ERROR

[Custom message]

A specific error occurred that requires custom handling (message varies)

500

MISSING_APPS_CONFIG

Something went wrong. Contact the administrator if the error persists

The required configuration for privacy apps is not found or inaccessible

500

ERROR_LOCKING_SOCKET

Something went wrong. Contact the administrator if the error persists

Our system failed to establish exclusive access to the communication socket

500

ERROR_SENDING_TO_SOCKET

Something went wrong. Contact the administrator if the error persistsrver is not ready yet, please try again later

Our system failed to send data through the communication socket

500

ERROR_RECEIVING_FROM_SOCKET

Something went wrong. Contact the administrator if the error persists

Our system failed to receive data from the communication socket

500

ERROR_DESERIALIZING

Something went wrong. Contact the administrator if the error persists

Our system failed to parse the output data from the privacy app

400

INVALID_PARAMS

Invalid parameter(s).

The provided parameters don't meet the required format or validation rules for the app input

400

INVALID_PARAMS

Error serializing parameters

Our system failed to convert the provided parameters into the required format

404

INVALID_URL

Invalid URL

The requested privacy app endpoint or resource was not found in our system

500

ERROR_LOADING_APP

Something went wrong. Contact the administrator if the error persists

Our system failed to initialize or load the requested privacy app

500

ERROR_LOADING_INSTANCE

Sign User Data and DVR

Prerequisites

Make sure you have key pair consisting of :

  1. publicKeyJWKS

privateKey

Read Generate Key Pair section for detail info.

Overview

We need to sign User Data and Data Verification Request (DVR) before sending a request to the zkPass service. This ensures that the payload is not tampered during transport.

Example Implementation

JWKS

The JSON Web Key Set (JWKS) is a set of keys containing the public keys used to verify any JSON Web Token (JWT) issued by the Authorization Server and signed, You can find a complete definition of JWKS here.

Upload your publicKeyJWKS so that it's accessible from the internet. This will be used by zkPass service to verify the validity of the user data.

Example of the uploaded publicKeyJWKS

JWS

A JSON Web Signature (abbreviated JWS) is an IETF-proposed standard (RFC 7515) for signing arbitrary data. This is used as the basis for a variety of web-based technologies including JSON Web Token. You can find a complete definition of JWS here.

This is an example code of how you can sign a JSON object as JWS format in Typescript. Let's say you uploaded your publicKeyJWKS to https://mywebsite/my-keys.json

Example for User Data

Below is the example of Query in DVR, this query will be included in full DVR

Below is the example of full DVR that will be generated into DVR Token

Output Example

After this section you should have :

  1. User Data Token : User Data in JSON Web Signature (JWS) format.

  2. DVR Token : DVR in JSON Web Signature (JWS) format.

Here's the example of User Data Token & DVR Token in JWS format.

{
  "keys": [
    {
      "x": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELOmrNI4A9ML4iGJXpYlaZiYGVCxB",
      "y": "k+evjhOZEbCLj17o/ZdfEv7dUZIRKRoZ1bud5Gq8OCItDlXkTyMrtWrhdA==",
      "kid": "q6ZFSOJcTiZWJWkvUshpFw5v20xstZN/T4lt4zpKsUg="
    }
  ]
}
import { SignJWT, importPKCS8 } from "jose";

async signDataToJwsToken(
    privateKey: string,
    userDataOrDVR: any
  ): Promise<string> {
    const verifyingKeyJwks = {
      jku: "https://mywebsite/my-keys.json",
      kid: "q6ZFSOJcTiZWJWkvUshpFw5v20xstZN/T4lt4zpKsUg="
    }
    
    const alg = "ES256";
    const importedPrivateKey = await importPKCS8(privateKey, alg);
    
    return await new SignJWT({ data: userDataOrDVR })
      .setProtectedHeader({
        alg: alg,
        jku: verifyingKeyJwks.jku,
        kid: verifyingKeyJwks.kid,
      })
      .sign(importedPrivateKey);
  }
{
  "testID": "SCREEN-7083-12345",
  "testName": "QualityHealth Comprehensive Screen",
  "testDate": "2023-08-27T14:00:00Z",
  "lab": {
    "name": "QualityHealth Labs",
    "ID": "QH801874",
    "address": "1234 Elm St, Oakland, USA"
  },
  "subject": {
    "firstName": "Jane",
    "lastName": "Doe",
    "dateOfBirth": "1985-12-12",
    "bloodType": "A+",
    "DNAInfo": {
      "markers": {
        "APOE": ["E3", "E3"],
        "BRCA1": "Normal",
        "MTHFR": ["C677T", "A1298C"]
      },
      "haplogroups": {
        "paternal": "R1b1",
        "maternal": "H1a1"
      }
    },
    "contact": {
      "email": "jane.doe@gmail.com",
      "phone": "650-555-1234"
    },
    "address": {
      "street": "789 Oak Street",
      "city": "San Jose",
      "state": "CA",
      "zip": "95134"
    }
  },
  "measuredPanelsNgML": {
    "amphetamines": 0,
    "cocaine": 8,
    "opiates": 102,
    "benzodiazepines": 0
  }
}
[
  {
    "assign": {
      "blood_test_status": {
        "and": [
          {
            "==": [{ "dvar": "lab.ID" }, "QH801874"]
          },
          {
            "==": [{ "dvar": "testID" }, "SCREEN-7083-12345"]
          },
          {
            "~==": [{ "dvar": "subject.firstName" }, "jane"]
          },
          {
            "~==": [{ "dvar": "subject.lastName" }, "doe"]
          },
          {
            "==": [{ "dvar": "subject.dateOfBirth" }, "1985-12-12"]
          },
          {
            "==": [{ "dvar": "measuredPanelsNgML.amphetamines" }, 0]
          },
          {
            "<=": [{ "dvar": "measuredPanelsNgML.cocaine" }, 10]
          }
        ]
      }
    }
  },
  { "output": { "result": { "lvar": "blood_test_status" } } }
]
{
  "zkvm": "r0",
  "dvr_title": "My DVR",
  "dvr_id": "d5bba9dc-e90c-456d-811c-79aa73755f54",
  "query_engine_ver": "1.3.0",
  "query_method_ver": "24555fe163e523bb313df8355ca39fbd79d49a02c642373b19c2a31cfc7a78d",
  "query": "[{\"assign\":{\"blood_test_status\":{\"and\":[{\"==\":[{\"dvar\":\"lab.ID\"},\"QH801874\"]},{\"==\":[{\"dvar\":\"testID\"},\"SCREEN-7083-12345\"]},{\"~\":[{\"dvar\":\"subject.firstName\"},\"jane\"]},{\"~\":[{\"dvar\":\"subject.lastName\"},\"doe\"]},{\"==\":[{\"dvar\":\"subject.dateOfBirth\"},\"1985-12-12\"]},{\"==\":[{\"dvar\":\"subject.contact.email\"},\"jane.doe@gmail.com\"]},{\"==\":[{\"dvar\":\"measuredPanelsNgML.amphetamines\"},0]},{\"<=\":[{\"dvar\":\"measuredPanelsNgML.cocaine\"},10]}]}}},{\"output\":{\"name\":{\"dvar\":\"subject.firstName\"}}},{\"output\":{\"email\":{\"dvar\":\"subject.contact.email\"}}},{\"output\":{\"result\":{\"lvar\":\"blood_test_status\"}}}]",
  "user_data_requests": [
    {
      "key": "",
      "value": {
        "jku": "https://raw.githubusercontent.com/gl-zkPass/zkpass-sdk/main/docs/zkpass/sample-jwks/issuer-key.json",
        "kid": "k-1"
      }
    }
  ],
  "dvr_verifying_key": {
    "jku": "https://raw.githubusercontent.com/gl-zkPass/zkpass-sdk/main/docs/zkpass/sample-jwks/verifier-key.json",
    "kid": "k-1"
  }
}
{
  "userDataToken": "eyJ0eXAiOiJKV1QiLCJqa3UiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZ2wtemtQYXNzL3prcGFzcy1zZGsvbWFpbi9kb2NzL3prcGFzcy9zYW1wbGUtandrcy9pc3N1ZXIta2V5Lmpzb24iLCJraWQiOiJrLTEiLCJhbGciOiJFUzI1NiJ9.eyJkYXRhIjp7InRlc3RJRCI6IlNDUkVFTi03MDgzLTEyMzQ1IiwidGVzdE5hbWUiOiJRdWFsaXR5SGVhbHRoIENvbXByZWhlbnNpdmUgU2NyZWVuIiwidGVzdERhdGUiOiIyMDIzLTA4LTI3VDE0OjAwOjAwWiIsImxhYiI6eyJuYW1lIjoiUXVhbGl0eUhlYWx0aCBMYWJzIiwiSUQiOiJRSDgwMTg3NCIsImFkZHJlc3MiOiIxMjM0IEVsbSBTdCwgT2FrbGFuZCwgVVNBIn0sInN1YmplY3QiOnsiZmlyc3ROYW1lIjoiSmFuZSIsIl9maXJzdE5hbWVfemtwYXNzX3B1YmxpY18iOnRydWUsImxhc3ROYW1lIjoiRG9lIiwiZGF0ZU9mQmlydGgiOiIxOTg1LTEyLTEyIiwiYmxvb2RUeXBlIjoiQSsiLCJETkFJbmZvIjp7Im1hcmtlcnMiOnsiQVBPRSI6WyJFMyIsIkUzIl0sIkJSQ0ExIjoiTm9ybWFsIiwiTVRIRlIiOlsiQzY3N1QiLCJBMTI5OEMiXX0sImhhcGxvZ3JvdXBzIjp7InBhdGVybmFsIjoiUjFiMSIsIm1hdGVybmFsIjoiSDFhMSJ9fSwiY29udGFjdCI6eyJlbWFpbCI6ImphbmUuZG9lQGdtYWlsLmNvbSIsIl9lbWFpbF96a3Bhc3NfcHVibGljXyI6dHJ1ZSwicGhvbmUiOiI2NTAtNTU1LTEyMzQifSwiYWRkcmVzcyI6eyJzdHJlZXQiOiI3ODkgT2FrIFN0cmVldCIsImNpdHkiOiJTYW4gSm9zZSIsInN0YXRlIjoiQ0EiLCJ6aXAiOiI5NTEzNCJ9fSwibWVhc3VyZWRQYW5lbHNOZ01MIjp7ImFtcGhldGFtaW5lcyI6MCwiY29jYWluZSI6OCwib3BpYXRlcyI6MTAyLCJiZW56b2RpYXplcGluZXMiOjB9fX0.TwoIFlHXnKjhKGlhW6tCfuc20pgvFFUmZ_wEMBvrQyKaub7aN3SBT0_zPPeDn_EUi2UP6eo0pr7ofNjfXEtgsA",
  "dvrToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJkYXRhIjp7Inprdm0iOiJyMCIsImR2cl90aXRsZSI6Ik15IERWUiIsImR2cl9pZCI6ImQ1YmJhOWRjLWU5MGMtNDU2ZC04MTFjLTc5YWE3Mzc1NWY1NCIsInF1ZXJ5IjoiW3tcImFzc2lnblwiOntcImJsb29kX3Rlc3Rfc3RhdHVzXCI6e1wiYW5kXCI6W3tcIj09XCI6W3tcImR2YXJcIjpcImxhYi5JRFwifSxcIlFIODAxODc0XCJdfSx7XCI9PVwiOlt7XCJkdmFyXCI6XCJ0ZXN0SURcIn0sXCJTQ1JFRU4tNzA4My0xMjM0NVwiXX0se1wifj09XCI6W3tcImR2YXJcIjpcInN1YmplY3QuZmlyc3ROYW1lXCJ9LFwiamFuZVwiXX0se1wifj09XCI6W3tcImR2YXJcIjpcInN1YmplY3QubGFzdE5hbWVcIn0sXCJkb2VcIl19LHtcIj09XCI6W3tcImR2YXJcIjpcInN1YmplY3QuZGF0ZU9mQmlydGhcIn0sXCIxOTg1LTEyLTEyXCJdfSx7XCI9PVwiOlt7XCJkdmFyXCI6XCJzdWJqZWN0LmNvbnRhY3QuZW1haWxcIn0sXCJqYW5lLmRvZUBnbWFpbC5jb21cIl19LHtcIj09XCI6W3tcImR2YXJcIjpcIm1lYXN1cmVkUGFuZWxzTmdNTC5hbXBoZXRhbWluZXNcIn0sMF19LHtcIjw9XCI6W3tcImR2YXJcIjpcIm1lYXN1cmVkUGFuZWxzTmdNTC5jb2NhaW5lXCJ9LDEwXX1dfX19LHtcIm91dHB1dFwiOntcIm5hbWVcIjp7XCJkdmFyXCI6XCJzdWJqZWN0LmZpcnN0TmFtZVwifX19LHtcIm91dHB1dFwiOntcImVtYWlsXCI6e1wiZHZhclwiOlwic3ViamVjdC5jb250YWN0LmVtYWlsXCJ9fX0se1wib3V0cHV0XCI6e1wicmVzdWx0XCI6e1wibHZhclwiOlwiYmxvb2RfdGVzdF9zdGF0dXNcIn19fV0iLCJxdWVyeV9lbmdpbmVfdmVyIjoiMS4zLjAiLCJxdWVyeV9tZXRob2RfdmVyIjoiMjQ1NTVmZTE2M2U1MjNiYjMxM2RmODM1NWNhMzlmYmQ3OWQ0OWEwMmM2NDIzNzNiMTljMmEzMWNmYzdhNzhkIiwidXNlcl9kYXRhX3JlcXVlc3RzIjp7IiI6eyJ1c2VyX2RhdGFfdXJsIjpudWxsLCJ1c2VyX2RhdGFfdmVyaWZ5aW5nX2tleSI6eyJLZXlzZXRFbmRwb2ludCI6eyJqa3UiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZ2wtemtQYXNzL3prcGFzcy1zZGsvbWFpbi9kb2NzL3prcGFzcy9zYW1wbGUtandrcy9pc3N1ZXIta2V5Lmpzb24iLCJraWQiOiJrLTEifX19fSwiZHZyX3ZlcmlmeWluZ19rZXkiOnsiS2V5c2V0RW5kcG9pbnQiOnsiamt1IjoiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2dsLXprUGFzcy96a3Bhc3Mtc2RrL21haW4vZG9jcy96a3Bhc3Mvc2FtcGxlLWp3a3MvdmVyaWZpZXIta2V5Lmpzb24iLCJraWQiOiJrLTEifX19fQ.3sGHmQZ_lbEJei9OKTxlshDoYs2wWurjEyiA767BEBrxU5u5fSV-s1qHghVlp748MqZf_cLb7j6g3MrsL34wbw"
}