Only this pageAll pages
Powered by GitBook
1 of 76

zkPass Developer's Guide

Loading...

ZKPASS OVERVIEW

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

zkPass Modules

DVR

Data Verification Request

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

SDK Tutorial

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

API Reference

Loading...

Classes

Loading...

Functions

Loading...

Loading...

Loading...

Type Aliases

Loading...

Loading...

Interfaces

Loading...

Constants

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Glossary

Loading...

Loading...

Loading...

Trust Models

The zkPass Service employs different trust models with regard to data privacy, data integrity, and computation integrity.

Data Privacy Trust Model

zkPass primarily uses a Trusted Execution Environment (TEE) to protect the input's privacy and integrity. (Although TEE can also be used to protect the execution of proof computation, zkPass relies on the trustless ZKP technology for execution integrity, as explained in the next point.). The zkPass server has two main components that process the user’s data input:

  • Digital signature verification on the user’s data

  • ZK proof calculation, which takes the user’s data as the input.

Because the data must be unencrypted during processing, both components must be running under TEE to ensure that the user’s data privacy is always protected throughout the entire process. Homomorphic Encryption (HE) cannot be applied here as HE has minimal capabilities in terms of what computation it can perform, while both DSA and ZKVM involve very complex computations. Therefore, the data privacy protection in zkPass is based on a Trusted Model, in which the user basically must trust that the zkPass server is implemented correctly and holistically to protect the privacy of the user’s data.

Data Integrity Trust Model

The zkPass service takes two inputs: the signed credential and the signed DVR. Both inputs need to be DSA-verified by the zkPass service to make sure they are not tampered with. The DSA verification can occur either inside or outside the ZKP proof function. Therefore, there can be two different approaches to the data integrity model:

  • Trusted Data Integrity The digital signature verification on the credential and DVR is performed in TEE but outside of the ZKP proof function.

  • Trustless Data Integrity The digital signature verification on the credential and DVR is performed inside the ZKP proof function running in the TEE.

While the trustless data integrity model is the preferred one, the DSA verification computation is quite heavy to run inside the ZKVM engine. Currently, there are some limitations on how much processing you can perform on a ZKVM. Due to this constraint, the current proposal is to choose the Trusted Model for data integrity as it is practically feasible to implement and reasonably secure. However, it is very possible that we can use the trustless model in the near future if the underlying ZKVM engine has improved its processing capabilities.

Computation Integrity Trust Model

zkPass uses a ZKVM engine (Zero Knowledge Virtual Machine) to ensure the proof function is executed in a verifiable computation environment. In this regard, the proof generation feature is based on the Trustless Model, in which the Verifier can confidently confirm if the generated proof and output are valid without the need to trust the zkPass server or any other third-party entity.

The following table summarizes the zkPass trust models:

Trust Model

Data Privacy

Trusted (via TEE)

Data Integrity

Trusted (via TEE)

Computation Integrity

Trustless (via ZKVM)

The trusted model for data privacy, which is less desirable, is the result of the trade-off of moving the ZKP computation from the user’s private space into an external server managed by a third-party entity. Nevertheless, as described in the zkPass Service design, we believe that the proposed trust models are sufficiently secure enough and provide an effective and practical solution for the proof system needed for the didPass ecosystem.

Deployment

The zkPass Service offers flexible hosting options to meet diverse organizational needs and data management preferences. Understanding these options is crucial for choosing the most suitable deployment strategy that aligns with your organizational requirements, control levels, and data privacy standards.

There are three main hosting options for the zkPass Service:

Each hosting option for the zkPass Service comes with its own set of advantages and considerations. Public cloud hosting offers ease and scalability, private cloud hosting provides additional control and customization, and on-premise hosting delivers the utmost in data sovereignty and security. Organizations should carefully assess their specific needs, regulatory requirements, and resource capabilities to select the most appropriate hosting solution for their implementation of the zkPass Service.

Public-cloud hosting
Private-cloud hosting
On-premise hosting

Public-Cloud Hosting

Our Public Cloud Hosting option for the zkPass Service is like a communal digital space that's open and accessible to everyone. We take care of hosting the service, making it readily available for public use. This approach is perfect for those who want the benefits of cloud technology without the hassle of managing it themselves.

Advantages of Public Cloud Hosting

Choosing Public Cloud Hosting means you get the best of cloud computing, which includes:

  • Cost Efficiency Say goodbye to heavy investments in infrastructure. With public cloud hosting, you reduce your overhead costs as we handle the technical setup.

  • High Availability Our service is always up and running, ensuring you can access it whenever you need it.

  • Scalability As your organization grows or your needs change, scaling up or down is easy and flexible. This means the service adapts to your demand, not the other way around.

  • Effortless Management We keep the zkPass Service in top shape with regular updates and maintenance, all taken care of by our expert cloud service providers.

Enhanced Security in the Cloud

While the public cloud is all about accessibility, we haven't compromised on security. To ensure the highest level of protection, we run the zkPass Service within a Trusted Execution Environment (TEE). This means even in a shared cloud space, the zkPass operates in a secure, isolated environment, safeguarding all operations and data against external threats.

In summary, Public Cloud Hosting for zkPass is an ideal solution for those seeking a balance between accessibility, scalability, and cost-effectiveness, without compromising on the security and reliability of the service.

Private-Cloud Hosting

Private Cloud Hosting, also known as the Virtual Private Cloud (VPC), for the zkPass service, is the go-to choice for organizations seeking a heightened level of control over their data and the execution of Zero-Knowledge Proofs (ZKPs). This hosting option offers a dedicated cloud environment, essentially providing a private digital space exclusively for your organization's use.

Key Features of Private Cloud Hosting

  • Enhanced Control You have the reins when it comes to managing your data. This control extends to how ZKPs are executed, giving you the ability to tailor processes to your specific requirements.

  • Customization Capabilities Every organization has unique needs, and private cloud hosting caters to this by offering the ability to customize your cloud environment to fit your specific operational parameters.

  • Data Control with Cloud Benefits While you enjoy comprehensive control over your data, you also benefit from the inherent advantages of cloud infrastructure, like scalability and operational efficiency. This means your hosting can grow and adapt to your organization.

Security Considerations in Private Cloud

In a private cloud setting, the zkPass service may operate differently compared to the public cloud. One key difference is that the zkPass service in a private cloud might not always run within a Trusted Execution Environment (TEE). This decision is often influenced by the specific security needs and infrastructure capabilities of your organization. Therefore, it's important to assess and implement additional security measures as needed to ensure that your data remains protected and your operations stay secure.

In conclusion, Private Cloud Hosting for zkPass is ideal for organizations that require a high degree of control and customization in their data management, alongside the flexibility and scalability of cloud infrastructure. This option is particularly suitable for those who have specific operational or security requirements that go beyond the scope of public cloud offerings.

Introduction

Welcome to the zkPass Developer's Guide. This document is engineered for developers, software architects, and technical leads who aim to implement Zero-Knowledge Proof (ZKP) functionalities in their applications via a scalable, cloud-based architecture. Through a Proof-As-a-Service model, zkPass offers an API-driven approach for ZKP computations, abstracting away the computational complexity and focusing on seamless integration.

zkPass is a specialized Proof-As-a-Service that enables the efficient execution of Zero-Knowledge Proofs (ZKPs) within a Trusted Execution Environment (TEE). The service exposes a set of APIs and an SDK library (zkpass-client) to facilitate the delegation of ZKP computational tasks to a cloud-based environment. This architectural choice is particularly beneficial for client devices with resource constraints, allowing for scalability without sacrificing data privacy.

Key Technical Features

zkPass Modules

The heart of zkPass is the zkPass module model. This is a privacy-preserving application which features the following characteristics:

  • Data Privacy zkPass uses state-of-the-art Zero Knowledge Proof (ZKP) to maintain data confidentiality. In addition, the cloud-based architecture operates within a TEE, providing an additional layer of security against the risks inherent to data centralization.

  • Verifiable Computation With Zero Knowledge Proof (ZKP) technology, the execution of zkPass modules becomes verifiable, ensuring the integrity and security of the code. This means that any attempt to tamper with or alter the application's code can be detected and prevented. This verifiability is crucial for maintaining trust in zkPass modules in a trustless fashion, as it ensures that the application operates as intended and that user data remains secure and confidential.

  • Scalable Computation Architecturally designed to serve a range of devices, from mobile endpoints to data centers.

  • Easy Integration The zkPass module presents high-level concepts that are easy to grasp, enabling a swift integration environment for third-party applications seeking to implement privacy-protecting features. This design ensures that developers can quickly understand and incorporate these concepts, facilitating the seamless addition of privacy measures into their applications.

While zkPass offers many advantages, it's crucial to note that the service-centric approach implies that sensitive user data will be processed on a centralized server. However, the TEE environment aims to mitigate this by adding an extra layer of security, ensuring the confidentiality and integrity of user data.

What Lies Ahead?

Continue to the subsequent sections for granular setup guidelines, extensive API documentation, code examples, and architectural discussions aimed to empower you to exploit the full capabilities of zkPass.

Thank you for considering zkPass for your application's ZKP requirements. We are eager to see your contributions to this evolving field!

Architecture

To address the limitations of the client-based proof system architecture, we introduce zkPass, a service-based proof system operating as a Proof-as-a-Service platform.

The defining characteristic of zkPass is the offloading of ZKP computations to a server operating within a Trusted Execution Environment (TEE). Users only need to initiate a service request through the zkpass-client SDK library, which then delegates the heavy computational tasks to the server side.

The zkPass is specifically designed to support privacy-preserving applications. It provides the client libraries and secure middle-layer infrastructure to implement applications that protect the privacy of user data and support a verifiable computation environment. zkPass uses ZKVM (Zero Knowledge Virtual Machine) as the underlying core proof system on which the applications run. In the future, zkPass may also support a new proof system other than Zero Knowledge Proof.

The high-level architecture view of the zkPass is illustrated here:

Currently, zkPass implements one such zkPass module, the Data Verification Request (DVR). Future releases of zkPass can support other forms of privacy-protecting applications. This guide will focus primarily on two things: the service infrastructure of zkPass and the DVR application.

The next section describes each component of the zkPass.

zkPass Components

The zkPass is a cloud-based infrastructure composed of three main components: zkPass Service, zkPass Modules, and zkPass Client Library.

zkPass Service

The zkPass Service has 2 parts:

  • zkPass Web Service zkPass Web Service provides the REST API for the zkPass module clients. This endpoint accepts parameters that are defined by the zkPass module and forwards them to the ZkPass Host for the actual execution of the application. The web service operates in an untrusted environment. The clients of the zkPass module communicate with the web service via the zkPass Client Library.

  • zkPass Host zkPass Host operates within a Trusted Execution Environment (TEE), ensuring complete isolation and security from external threats. It interacts with the zkPass Web Service through a secure, specialized channel, receiving inputs for the zkPass module that are forwarded by the zkPass Web Service. The main function of the zkPass Host is to load the zkPass module executable module and execute it within the TEE. Additionally, the client of the zkPass module can perform end-to-end encryption with the zkPass Host to protect the privacy of user data being sent to the zkPass Service. This setup ensures that user data remains confidential and secure throughout the entire process.

zkPass Modules

The zkPass module is the heart of zkPass, creating higher-level abstractions and models that simplify integration and usage for third-party software. Its two main goals are:

  • Protecting the privacy of user data

  • Providing a verifiable computing environment

Pluggable Module

The zkPass module is implemented as a pluggable module, which is loaded by the zkPass Host and executed within a Trusted Execution Environment (TEE). While the data format for input and output is specific to each application, all input and output data must adhere to JWT encoding standards. This modular design ensures flexibility and security, allowing the zkPass module to operate seamlessly within the zkPass framework while maintaining the integrity and confidentiality of user data.

DVR

zkPass Client Library

The zkPass-client is an SDK client library that provides interfaces, types, and functions for interacting with zkPass modules. Currently, the zkPass-client supports the DVR module.

DVR Client

The DVR client facilitates interaction with the DVR module and offers the following functionalities:

  • Issuing zkPass proofs

  • Verifying zkPass proofs

  • Generating tokens

zkPass is designed to support multiple zkPass modules, with the current primary application being the Data Verification Request (DVR), detailed in the section. DVR uses the powerful Zero Knowledge Virtual Machine as the underlying proof system. DVR ensures robust data protection and trust, making it indispensable for developers aiming to incorporate advanced privacy-preserving features into their software with an intuitive and easy-to-use interface and expressive JSON-based query language.

On-Premise Hosting

For organizations with rigorous demands regarding data sovereignty and the security of their internal infrastructure, on-premise hosting of the zkPass Service is the ideal solution. This hosting model places the zkPass Service directly within your organization's data centers. By doing so, it ensures that your data remains entirely within your control and does not traverse external networks. This aspect is particularly crucial for organizations that handle highly sensitive information or are subject to stringent data protection regulations.

Key Benefits of On-Premise Hosting

  • Unmatched Data Control With on-premise hosting, you have the highest level of control over your data. It stays within the confines of your organization, reducing external risks and exposures.

  • Enhanced Security Compliance This model is tailored for organizations that need to adhere to strict compliance and regulatory standards. Keeping the zkPass Service on-premise means you can align it more closely with your internal security protocols and compliance requirements.

  • Customized to Your Infrastructure On-premise hosting allows you to integrate the zkPass Service seamlessly with your existing IT infrastructure. This integration can be tailored to meet the specific needs and security standards of your organization.

Considerations for On-Premise Hosting

Unlike cloud-based options, on-premise hosting of zkPass does not inherently require the service to run within a Trusted Execution Environment (TEE). This flexibility allows for a more customized security approach, where you can decide the best way to secure the service based on your infrastructure and security policies. However, it also means that ensuring the highest security standards rests largely on your organization’s ability to implement and maintain robust security measures within your own IT environment.

In summary, on-premise hosting of the zkPass Service is the premium choice for organizations that prioritize absolute control over their data and have the capability to manage high-level security requirements internally. This option provides a bespoke solution that aligns perfectly with stringent internal policies and regulatory needs, ensuring data remains secure and under your organization’s direct oversight.

DVR

DVR Client Roles

The DVR follows a robust trust model inspired by the W3C Decentralized Identifiers (DID) standards. Within the zkPass ecosystem, we define three client roles which participate in the zkPass ecosystem.

Depending on the application, the client of DVR can take one of these roles:

  1. Data Issuer The entity responsible for issuing the original data that requires protection.

  2. Data Holder (User) The individual whose confidential data is being protected.

  3. Proof Verifier The service or application that sets the requirements or conditions on the user data. It verifies the zero-knowledge proof, which contains the result of the requirements.

This multi-faceted trust model allows the proper flow of data and communications among the DVR stakeholder clients and ensures that the user’s confidential information remains protected and secure.

User Data

User data encapsulates a spectrum of sensitive and confidential attributes, credentials, or claims, ranging from driver's licenses and passports to financial credentials such as bank account details.

Schema-Agnostic Design

One of the standout features of zkPass is its adaptability to various data structures. The framework is designed to be "schema-agnostic," meaning it doesn't impose a specific schema on the data. This flexibility allows the Data Issuer to work with different types of data structures seamlessly.

Data Encoding Requirements

For Data Issuers, the only requirement is that the data should be encoded in JSON format. This standardization enables easy integration into the zkPass workflow without necessitating specific data schematization.

Secure Data Consumption

At the end of the data flow, the consumer of this user data is the DVR app which is running inside the zkPass Host. This component operates in a secure and isolated environment, ensuring the integrity and confidentiality of the user data being queried.

Signing and Encrypting User Data

In the context of secure data transmission, the user data content needs to be encapsulated within a multi-layered cryptographic token for confidentiality and integrity. Specifically, this token consists of two nested layers:

  1. This double-layered security ensures that the user data remains confidential and accessible only by authorized components during transit.

By employing this nested-token architecture, the user data can be securely transmitted through the network. Only the Data Issuer, Data Holder, and zkPass Host are allowed to access the user data's content. This not only maintains the confidentiality and integrity of the user data but also prevents unauthorized parties from tampering with or viewing the token during its transit to the zkPass Service.

SDK Objectives

The zkPass SDK is the resource for integrating zkPass's robust privacy-protecting privacy applications into your client or service using Zero-Knowledge Proofs (ZKPs) functionalities provided by the zkPass Service. This SDK serves as an all-encompassing interface and library designed for third-party applications to use for accessing the zkPass Service framework.

Objectives of the zkPass SDK

The zkPass Software Development Kit is created with a set of core objectives in mind, ensuring that it not only meets but exceeds the expectations and needs of developers. Here's an overview of the key goals of the zkPass SDK:

  1. High-Performance Performance is a critical aspect of the zkPass SDK. It is designed to handle complex proof computations efficiently, ensuring fast and reliable performance even under demanding conditions. This ensures that applications using zkPass can operate smoothly without performance bottlenecks.

  2. Robust Security At its core, zkPass SDK is built with ZKP technologies. It prioritizes the protection of user data and the integrity of verification processes, implementing advanced cryptographic techniques to safeguard against potential vulnerabilities and threats.

  3. Multi-Platform Support Understanding the diverse ecosystem of applications, the zkPass SDK is developed to be cross-platform compatible. Currently, it can be seamlessly integrated into three platform configurations: Node.js/Linux, ReactNative/Android, and Rust/Linux.

  4. Innovation-Driven The zkPass SDK is at the forefront of technological innovation, especially in the realm of service-based proof systems. It continually evolves to include the latest advancements in the field of ZKP, providing developers with cutting-edge tools to build sophisticated and modern applications.

  5. Comprehensive Documentation and Support To ensure developers can make the most of the SDK, comprehensive documentation and support for the privacy apps are provided. This includes detailed guides, API documentation, and responsive support channels to assist developers through any challenges they may encounter.

High Level View

Data Verification Request (DVR) is the main zkPass module running within the framework of the zkPass Service.

Overview

The DVR application facilitates the verification of user data while maintaining its privacy. To use the DVR and participate in the DVR workflow, the DVR clients take one of the following client roles: Data Issuer, Data Holder (the user), and Proof Verifier.

The Proof Verifier sets the criteria for users to access certain services or resources. These criteria are encoded as a query script written by the Proof Verifier client, and the script represents business logic that verifies against the user's documents.

Although the user owns their data, it is typically issued and signed by a trusted entity known as the Data Issuer. The zkPass service processes the business logic specified in the DVR query script, generating a Zero Knowledge proof and the query output. The Proof Verifier then uses this proof and output to determine if the user meets the specified criteria. Throughout this process, the user’s data is never transmitted to the Proof Verifier, ensuring its privacy. The Verifier only receives the proof and the relevant output.

Architecture

The high-level view of the DVR application and its clients is illustrated here.

It should be noted that with this server-centric approach, the user's sensitive input data is no longer confined to their device but is instead processed in a centralized server. This shift necessitates a degree of trust to ensure the confidentiality of the user's input. To alleviate this concern, zkPass Service runs the zkPass module, such as the DVR, within a Trusted Execution Environment (TEE). This secure and isolated environment aims to provide an additional layer of protection, safeguarding the privacy of user data while allowing for the efficient execution of DVR queries. In other words, zkPass can still protect data confidentiality through the trusted privacy model.

Workflow Diagram

The diagram of the DVR for the holder-centric workflow is depicted below.

Beyond merely transferring the computational load of proof generation from the client device to the server, DVR incorporates a robust JSON-based query language (DVR Query) that empowers developers to articulate specific requirements or conditions to be applied to the user's data. This JSON query is executed within the Zero-Knowledge Virtual Machine (ZKVM), resulting in a cryptographic proof that verifies the execution has occurred exactly as intended, without any alterations.

The DVR inherits the two pivotal features from its client-side predecessor, enhancing them within its server-centric architecture:

  1. Trusted Data Privacy By generating a cryptographic proof, DVR ensures that the underlying data remains confidential. The Proof Verifier can confirm the proof's validity without ever needing to access the original sensitive data. While the service-based approach does introduce a new set of concerns, which is the need to trust a centralized server with sensitive user data, DVR mitigates this issue by operating within a TEE. This adds an extra layer of security to maintain data integrity and confidentiality in an isolated and secure centralized computer.

  2. Query Execution Transparency The cryptographic proof generated by ZKVM serves as an immutable record that the query has been executed faithfully, meeting all specified conditions or requirements. Unlike often rigid proof functions found in client-side implementations, DVR offers an easy-to-use JSON query language. This allows users to effortlessly adjust to varying logic to enforce data requirements or conditions.

This advanced feature set not only alleviates computational constraints but also offers a highly flexible, secure, and transparent way for developers to implement privacy-centric logic within their applications.

Transitioning from a client-centric to a service-oriented proof system, the DVR application and the zkPass Service strive to deliver a scalable, efficient framework that accommodates a wide range of devices with diverse computational resources. It does so without compromising its commitment to data privacy and transparent execution. Moreover, it incorporates a versatile JSON-based DVR query language that is adaptable to any user data schema, offering users even greater flexibility.

API Key

Please keep your API Key and Secret Key safe—don't share them with anyone else

Key Concepts

Understanding the DVR and its functionalities revolves around comprehending three fundamental concepts that form the backbone of the system. These concepts are integral to the operations of DVR running on zkPass Service and are crucial for anyone looking to effectively utilize or develop with this application.

The diagram below illustrates the relationship among the three:

At a fundamental level, the user data and the DVR Info, which contains the query, act as essential inputs to the DVR/zkPass. These two components are necessary for the generation of the zkPass proof.

Pipeline for Generating zkPass Proof

For a more comprehensive understanding of the zkPass proof creation, examining the query processing pipeline provides insight into how this process unfolds.

The user data is modeled after the , which are structured pieces of information associated with a particular subject. Unlike the Verifiable Credentials, which adhere to rigorous and complex formatting standards, our user data model offers flexibility. It's engineered to accommodate any user data schemas, including the Verifiable Credentials.

In the app architecture, the individual or system who actually owns the data is referred to as the Data Holder or User. However, this data is initially provided by another party, known as the Data Issuer.

Inner Token (for signing) This is the user data that gets signed by the Data Issuer into a token. This digital signature guarantees that the token's origin and integrity can be verified at a later stage. Typically, this signed token is then transmitted from the Data Issuer to the Data Holder. Upon receipt, the Data Holder's application allows the user to visually inspect the content of their data. This ensures transparency while maintaining the token's secure and authenticated state.

Outer Token (for encrypting) The user data token, initially signed by the Data Issuer, undergoes another layer of security before it's sent to the zkPass Service. The Data Holder's application encrypts this signed token into a format. The reason for this additional encryption is to restrict access to the token's content while it's being transferred. Specifically, only the DVR app running in the zkPass Host process—a key component within the zkPass Service that operates in a Trusted Execution Environment (TEE)—is authorized to decrypt and view the content of the user data.

Ease of Use The primary aim of the zkPass SDK is to provide an intuitive and user-friendly interface, ensuring minimal development coding and time for integration with the privacy-preserving apps running on the zkPass Service. This objective focuses on simplifying the process of incorporating privacy apps such as the functionalities into applications, making it accessible even to those with limited experience in working with Zero-Knowledge Proofs.

In summary, the zkPass SDK has been developed with a focus on usability, performance, security, and innovation, and it supports three different platforms. Currently, the primary application supported by the SDK is the . The SDK's comprehensive approach to development objectives makes it a powerful tool for developers looking to integrate advanced data verification and privacy-preserving features into their applications.

You need an API key and a secret key to use the zkPass service. Register on the to obtain your API and secret keys.

W3C's Verifiable Credentials
DVR
JSON Web Signature (JWS)
JSON Web Encryption (JWE)
DVR
DVR
zkPass portal
User Data
DVR (Data Verification Request
zkPass Proof
The layering of JWE and JWS on User Data
DVR Client Roles

zkPass Proof

A zkPass Proof is a token that the zkPass Service generates. It is a composite of several key components.

  • Zero-Knowledge Proof: This is the crux of the cryptographic proof generated by executing a specific query on user data using a Zero Knowledge Virtual Machine (ZKVM), which runs within a Trusted Execution Environment (TEE). It verifies that the query has been executed correctly while keeping the underlying data confidential.

  • Query Output: This results from the application running on the ZKVM. This output is intended to be shared, and the Zero-Knowledge Proof guarantees its integrity.

  • Metadata: This includes auxiliary information about the proof from the application's perspective. In the context of DVR, they are timestamps, the unique identifier for the Data Verification Request (DVR), and other contextual data that might be necessary for auditing or verification.

Pipeline for zkPass Proof

The zkPass proof is constructed in a DVR pipeline of processes that start with two main inputs: User Data and the DVR Info, as illustrated here.

Integrity and Authenticity

The zkPass Proof object is signed by the zkPass Service into a JSON Web Signature (JWS) token to ensure its authenticity and integrity. Any tampering with the proof token can be easily detected, providing an additional layer of security.

Role in Data Privacy

The zkPass Proof facilitates a paradigm where the Verifier does not need direct access to the original, sensitive data. The Verifier can confirm the validity of a specific claim about the data by examining the Zero-Knowledge Proof. This is particularly powerful in scenarios that require stringent data privacy controls.

Transparency in Query Execution

The zkPass Proof isn't just about data confidentiality; it also ensures transparency in query execution. It is an immutable record, confirming that a particular query has been executed faithfully against the user data, adhering to all specified conditions or requirements.

Summary

The zkPass Proof is a robust, secure, and flexible mechanism designed to facilitate privacy-preserving data operations. It encapsulates the cryptographic proof of a query's accurate execution, the query's output, and relevant metadata, all wrapped in a secure, authenticated package. It provides a versatile and transparent way to conduct data operations while maintaining the highest data privacy and integrity standards.

Data Issuer

The Data Issuer only needs to follow this step for integration with the zkPass Service:

Sample Implementation

Sample codes for the Data Issuer implementation follow. Each step is explained in detail in the subsections. The code is also available on the zkpass-sdk repo, as shown here:

Data Holder

The Data Holder should follow four steps to integrate with zkPass:

Sample Implementation

Sample codes for the Data Holder implementation follow. Each step is explained in detail in the subsections. The code is also available on the zkpass-sdk repo, as shown here:

Providing User Data Retrieval API

Providing a REST API to retrieve the user data

The Data Issuer is required to expose a REST API that facilitates secure user data token retrieval. The API should be designed to authenticate the user robustly, ensuring that only the legitimate owner can access the data. The zkPass SDK does not dictate the precise authentication mechanisms, API semantics, or response formats, providing developers the flexibility to implement an approach best suited to their application's architecture.

The Data Issuer needs to make sure the user data is in JSON encoding. The DVR app architecture does not dictate the schema or structure of the user data, however, JSON encoding is required.

By conforming to these guidelines, Data Issuers contribute to the robustness and security of the DVR app infrastructure, ensuring an optimized and secure experience for all users involved.

Dvr Module Client Integration

Signing the User Data

As the authority provisioning sensitive user data, the Data Issuer plays a critical role in the DVR ecosystem. To ensure the authenticity of the user data, the Data Issuer must sign this sensitive information into a JWS (JSON Web Signature) token. The signing of the user data by the Data Issuer is illustrated by part of the DVR/zkPass call sequence, which is highlighted in red below:

The Dvr module client SDK library provides a specialized utility method for this purpose: callDvrGenerateUserDataToken. How to digitally sign the user data using the Dvr module client SDK library is illustrated by the code snippet below.

// Step 1: Instantiate DvrModuleClient
const dvrModuleClient = new DvrModuleClient({
      baseUrl: SERVICE_URL,
      apiKey: API_KEY,
      secretApiKey: API_SECRET,
    });
//
// Step 2: Call the DVR module client's callDvrGenerateUserDataToken
//         This is to digitally-sign the user data.
const userDataToken = dvrModuleClient.callDvrGenerateUserDataToken(
      signingKey,
      JSON.stringify(data),
      verifyingKey
    );

Parameters passed to callDvrGenerateUserDataToken:

  • signingKey This is the signing private key owned by the Data Issuer.

  • JSON.stringify(data) This is a stringified JSON user data.

  • verifyingKey This is a key to validate user data token.

Providing REST API for user data retrieval
Retrieving the DVR from the Proof Verifier
Retrieving the user data from the Data Issuer
Generating the ZkPass Proof from the two inputs: DVR and user data
Sending the ZkPass Proof to the Proof Verifier for the proof verification

1. Providing DVR Retrieval API

Providing a REST API to retrieve the DVR

The Proof Verifier must also define a mechanism through which users can retrieve the DVR token. The retrieval could be accomplished through various means, such as QR code scanning, a RESTful API, or other methods. zkPass SDK provides the flexibility to choose a retrieval mechanism most appropriate to the application's architectural design.

Signing the DVR data

The Proof Verifier is the entity responsible for defining the Data Verification Request (DVR) against which user data is verified. To accurately create DVR queries, the verifier must have an in-depth understanding of the user data format as provided by the Data Issuer. Utilizing zkPass Query Language, the verifier can reference specific fields within the user data using the notion of 'Variable'.

Upon receipt of a Zero-Knowledge Proof (ZKP) from the user, the verifier invokes zkPass.verifyProof function to authenticate the proof. A successful verification indicates that the user's data complies with all conditions stipulated in the DVR query.

The Proof Verifier is responsible for generating tokens for the DVR content. To achieve this, it must manage a public/private key pair specifically for digital signing. Additionally, the Proof Verifier should expose a standard JWKS (JSON Web Key Set) endpoint through a RESTful API for signature verification purposes. This endpoint serves as the source for obtaining the public key required to validate the DVR token's signature.

To facilitate the zkPass flow, the verifier must tokenize the DVR object into a JWT (JSON Web Token). In the inner token’s JWT header, the following parameters will be included by the verifier:

  • jku The URL where the public verification key can be retrieved.

  • kid The Key ID, is a unique identifier for the specific verification key in use.

zkpass-client Integration

In the implementation of the DVR retrieval codes, the Proof Verifier needs to digitally sign the DVR. This is done using the zkpass-client SDK library as illustrated here.

...

//
//  Step 1: Instantiate the zkpass_client object.
//
let zkpass_client = ZkPassClient::new(
    "", // This is the zkPass service URL, we don't provide the value because it's not needed on signing DVR flow
    ZkPassApiKey {
        api_key: "".to_string(),
        secret_api_key: "".to_string(),
    },
);

//
//  Step 2: Call zkpass_client.get_query_engine_version_info.
//          The version info is needed for DVR object creation.
//
let query_engine_version_info = zkpass_client.get_query_engine_version_info();

//
// Step 3: Create the DVR object
//
let dvr = DataVerificationRequest {
    zkvm: String::from(zkvm),
    dvr_title: String::from("My DVR"),
    dvr_id: Uuid::new_v4().to_string(),
    query_engine_ver: query_engine_version_info.0,
    query_method_ver: query_engine_version_info.1,
    query: serde_json::to_string(&query).unwrap(),
    user_data_requests: wrap_single_user_data_input(UserDataRequest {
        user_data_url: Some(String::from("https://hostname/api/user_data/")),
        user_data_verifying_key: PublicKeyOption::PublicKey(issuer_pubkey()),
    }),
    dvr_verifying_key: Some(PublicKeyOption::PublicKey(verifier_pubkey())),
};

//
//  Step 4: Call zkpass_client.sign_data_to_jws_token.
//          to digitally-sign the dvr data.
//
let dvr_token = zkpass_client
    .sign_data_to_jws_token(
        VERIFIER_PRIVKEY, 
        json!(dvr.clone()),
        Some(ep))
    .unwrap();
    
...

DVR Query

DVR defines a JSON query language that allows the Proof Verifier to check if the user has data that meets specific requirements, conditions, or constraints.

The query language is implemented by the DVR Query Engine component, which takes two inputs:

  • User Data This is the JSON data that is issued by the Data Issuer and is being inquired by the Proof Verifier to see if the data meets specific requirements or conditions. The data can follow any schema or structure as DVR does not set any specific format requirement on the user data.

  • DVR Query The query is a JSON-based script that sets the requirements or conditions for the user data. The query is expressed as a DVR scripting language and is included in the "query" field of the Data Verification Request (DVR) object. An example of the query would be “user must be either married or over 21 years of age”. The query is executed by the DVR Query Engine to produce the ZK Proof and the result of the query.

The goal of defining its own query language is to let the Proof Validator client be able to perform queries on the data using an expressive, flexible, intuitive, easy-to-use, and performant scripting language.

Proof Verifier

The Proof Verifier should take these two steps for the integration with zkPass:

Sample Implementation

A sample implementation for a proof verifier is provided on the zkpass-sdk repo, as shown here:

1. Retrieving the DVR

Retrieving the Data Verification Request (DVR) from the Proof Verifier

From Data Holder perspective, no integration with the Dvr module client SDK library is needed for this step.

The zkPass call sequence diagram, specifically steps 1–3, corresponds to the DVR retrieval process.

2. Retrieving the User Data

Retrieving the User Data from the Data Issuer

From Data Holder perspective, no integration with the Dvr module client SDK library is needed for this step.

The zkPass call sequence diagram, specifically steps 4–6, corresponds to the User Data retrieval process.

4. Verifying the Proof

Sending the ZkpassProof object to the Proof Verifier for verification

From Data Holder perspective, no integration with the Dvr module client SDK library is needed for this step.

The zkPass call sequence diagram, specifically steps 10–12, corresponds to the proof verification process.

2. Providing Proof Verification API

Providing a REST API to verify ZkPass Proof

Dvr Module Client Integration

In the proof verification API implementation, the Proof Verifier needs to verify the received ZkPass as shown here.

DVR Info

Data Verification Request Info

DVR Info

DVR Info is information that contains data and parameters that define the behavior of the DVR application as defined by the Proof Verifier. Each DVR Info has two main parts:

  1. Metadata (The Envelope of the DVR) Think of the metadata as the envelope that holds the DVR. It contains:

    • DVR ID This is like a tracking number for the request. It helps to know which question you're dealing with. This information is mainly used by the zkPass Service.

    • User Data Requests A mapping containing multiple UserDataRequest, which contains the User Data URL and the Public Key

      • User Data URL The URL to retrieve the user data referenced by the DVR Query variables. The Proof Verifier uses this information to tell the Data Holder where to download the user data content. A Data Issuer typically hosts the URL site. Note that this information is optional. The absence of this information means that the way to determine where to get the user data is embedded in the application business logic of the Data Holder.

      • Public Key This public key verifies that the user's data hasn't been tampered with.

  2. Query (The Actual Question) The real heart of the DVR is the query. This is the actual question or condition you want to check against the user's data. In zkPass, you write this query using a unique format called zkPass JSON Query Language. The query uses the concept of variables to reference elements that exist in the user data and compare the variable values with specific constant literals.

In this example query, variable "personalInfo.firstName" references the JSON element "firstName" whose parent element is "personalInfo". This element exists in the user data.

Signing and Encrypting DVR

Like user data, the Digital Verification Record (DVR) must transform into a secure, two-layered cryptographic token. Here's how it works:

This dual-layer token security model ensures that only the Proof Verifier, Data Holder, and zkPass Query Host can access the DVR's content while also allowing for verification of the token's authenticity. The design also guarantees that the DVR can be safely transmitted; unauthorized parties won't be able to modify or read the token as it moves through the network toward its final destination at the zkPass Service.

Summary

So, a DVR Info is a two-part package:

  1. Metadata tells you which DVR you're dealing with and makes sure the user data is verifiable

  2. Query specifies what you want to know about the user's data

By understanding these parts, you can use DVR Query language to ask all sorts of specific questions about user data in a secure and organized way.

Processing Query

Processing the DVR Query

zkPass Service processes the DVR query contained in the DVR Info and the user data referenced by the query in a pipeline flow, as depicted below.

  1. Initialization of the Data Verification Request(DVR) The proof verification begins by creating a Data Verification Request (DVR). This record is essential as it holds the specific request or "query" that needs to be verified.

  2. Inputs for Verification There are two key pieces of information that the DVR Query Engine requires to perform verification:

    • The Query: This is the request for information or action that needs to be checked.

    • The User Data: This refers to any information related to the user that the query will use or check against.

  3. Processing by the DVR Query Engine The DVR Query Engine is the powerhouse where the actual verification takes place. This engine operates within the Zero-Knowledge Virtual Machine (ZKVM), a secure environment designed for processing these queries.

  4. Results of the Verification Once the query has been processed, there are two results produced:

    • The Zero-Knowledge Proof (ZK Proof) This is a verification result that proves the query was processed correctly without revealing any private details.

    • The Query Result This is the outcome of the query after it has been processed.

  5. Packaging the Results Both the ZK proof and the query result are bundled into a single package known as the zkPass Proof object. This object can then be used to confirm the integrity and accuracy of the query process without exposing any sensitive information.

Building Query Engine

Building the DVR Query Engine

The heart of the DVR application is the query engine, which implements the DVR app. The query engine is designed as a DVR Query language interpreter that runs on the ZKVM directly.

  1. DVR Query Engine Codes The core component, the DVR Query Engine, is programmed in the Rust language. Rust is known for its safety and performance, making it an excellent choice for building reliable and secure systems.

  2. Compilation to Assembly Code To integrate with the Zero-Knowledge Virtual Machine (ZKVM), the DVR Query Engine is compiled into assembly code. This compilation is done using a specialized set of tools known as the compiler toolchain, which is specifically designed for the ZKVM environment. This ensures that the Query Engine is compatible with the security and operational requirements of the ZKVM.

  3. Build Outputs After the compilation process, two primary outputs are generated:

    • The Zero-Knowledge Proof Generator (ZK Proof Generator) This module is responsible for creating cryptographic proofs that confirm the validity of a query without revealing any underlying data. It is an integral part of the DVR Query Engine.

    • The Zero-Knowledge Proof Verifier (ZK Proof Verifier) This is the counterpart to the Proof Generator. It is tasked with checking the validity of the proofs generated by the Proof Generator. The Proof Verifier is included in the zkpass-client library, allowing client applications to verify proofs independently.

Integration Guidelines

For successful integration into the DVR application workflow, each client stakeholder is advised to follow the guidelines specified in this documentation.

DVR Block Diagram

The call flow involving all stakeholders within the DVR application is depicted in the accompanying diagram below.

Call Sequence Diagram

The call sequence diagram for the interaction is provided here.

Detailed Explanations

The comprehensive workflow for zkPass is elaborated in the following sections, where each step is explained in detail.

Generate Dvr Token

(Step 1) The Data Holder initiates the process by requesting the Data Verifier to generate a DVR token. This request requires authentication, allowing the Proof Verifier to securely verify the identity of the requesting user.

Note: The API signature and payload format are determined by the specific implementation of the Proof Verifier. zkPass does not enforce any specific standards or structure.

(Step 2) Upon receiving the request, the Verifier creates the DVR, tailoring the query to the requirements of the user's core data. For an example of a DVR query, refer to [this example].

To ensure uniqueness, the Verifier generates a distinct DVR ID each time a new DVR is created. Once the DVR is constructed, it is signed and encapsulated as a JSON Web Signature (JWS) token to ensure its integrity and authenticity.

(Step 3) The Data Holder then receives the DVR token from the Data Verifier.

Generate User Data Token

(Step 4) With the DVR token, the Data Holder proceeds to collect user data based on the DVR's requirements. Like the previous call to the Verifier, this request also requires authentication.

Caching Consideration: If the required user data is already cached and valid (not expired), this API call can be skipped. In such cases, proceed directly to Step 3.

Note: The API signature and payload structure are specific to the Data Issuer's implementation. zkPass does not prescribe any particular format or details.

(Step 5) Upon validating the request, the Data Issuer retrieves the corresponding user data. It then signs and serializes this data into a JSON Web Signature (JWS) token to confirm its authenticity. Finally, the token is returned to the requesting Data Holder.

(Step 6) The Data Holder receives the user data token from the Data Issuer.

Generate Proof

(Step 7) With both the DVR token and the user data token in hand, the Data Holder initiates the proof generation process. This step involves:

  • Encrypting both tokens into JSON Web Encryption (JWE) tokens.

  • Wrapping the tokens into a RESTful API call to the zkPass Service.

The primary goal of this step is to execute the query defined in the DVR against the user data, generating both a Zero-Knowledge Proof (ZKP) and the query output.

The zkPass Service processes the proof generation request by:

  • Validating the signatures on both tokens.

  • Decrypting the tokens.

  • Executing the query in a secure, isolated environment—specifically, the zkPass Query Host running within a Trusted Execution Environment (TEE).

(Step 8) Upon successful execution, the zkPass Service constructs a zkPass Proof object, which encapsulates the query output. This proof is signed as a JWS token to ensure its authenticity. The zkPass Proof token is then returned to the Data Holder.

zkPass Proof Components: The zkPass Proof object includes:

  • The cryptographic Zero-Knowledge Proof.

  • The query output.

  • Metadata about the proof.

(Step 9) The Data Holder receives the zkPass Proof token.

Verify Proof

(Step 10) With the zkPass Proof token, the Data Holder requests the Data Verifier to verify the proof. The proof token is provided as the sole input parameter.

Note: The API signature and payload schema for the Verifier are implementation-specific. zkPass does not impose any standardized format or structure.

(Step 11) Upon receiving the request, the Verifier:

  • Validates the signature on the proof token.

  • Uses the verify_zkpass_proof function from the zkPass-client library to perform ZKP verification. This step involves validating the cryptographic seal generated by the ZKVM in the zkPass Query Host process and extracting the query output from the seal.

(Step 12) After successfully verifying the zkPass Proof and extracting the query output, the Verifier returns the query results to the Data Holder.

Query Grammar

Data Types

The following are the supported basic data types by the DVR Query language:

  • Integer A signed 64-bit integer data type. Example: 10, -12

  • String A sequence of characters. Example: "Hello, world!"

  • Boolean A binary value that can be either true or false

Operators

The list of supported operators:

  • Boolean Operators:

    • or

    • and

  • Relational Operators: >, >=, <, <=

    • Applies to integer

  • Equality Operators

    • Equality operator: == Applies to boolean, integer, and string. In the case of a string, this is a case-sensitive comparison.

    • Inequality operator: != Applies to boolean, integer, string

    • String-specific Relational Operations

      • ~!= Case-insensitive inequality operation on a string

      • ~== Case-insensitive equality operation on string

Variable and Literals

The zkPass Query language also defines the following concepts:

  • Variable The variable corresponds to the key name of the key/value json element in the query data. To reference nested elements in the json data, delimiter “.” is used as the path separator. The variable must appear on the left-hand side of a relational expression.

  • Literal (Constant) The constant value is compared to the variable's value. The literal must appear on the right-hand side of a relational expression. The data type of the literal must match that of the variable.

Grammar BNF

Query Example

3. Generating the Proof

Calling zkPass Service's generate_zkpass_proof REST API to create the ZkPass Proof

To generate the ZkPass Proof, the Data Holder needs to use the zkpass-client SDK library. The following section illustrates how the coding is done.

Dvr Module Client Integration

The zkPass call sequence diagram, specifically steps 7–9, corresponds to the proof generation process.

The Data Holder generates the proof by using the Dvr module client SDK library, as shown here.

The Data Holder first gets the DVR by calling the provided by the Proof Verifier.

The User Data retrieves the user data that is needed by the DVR by calling the provided by the Data Issuer.

Once the Data Holder receives the Zkpass Proof from the zkPass Service, it will pass it along to the Proof Verifier for verification. The Proof Verifier provides a for this purpose.

Example Query

Inner Token (for signing) This is the DVR data that gets signed by the Proof Verifier into a token. The signing ensures that the token's authenticity can be later verified. The signed DVR token is typically sent from the Proof Verifier to the Data Holder. Once received by the Data Holder application, the user can still view the content of the DVR for visual verification of what the query intends to check on the user data.

Outer Token (for encrypting) This is the previously signed DVR token which has been encrypted into a JSON Web Encryption (JWT) token by the Data Holder application. Prior to sending the signed DVR token to the zkPass Service, the Data Holder encrypts the token again by wrapping it with a token. This is to ensure that only the zkPass Query Host process (a critical component inside the zkPass Service), which runs in the Trusted Environment Environment (TEE), can decrypt and view the DVR's content while the data is in transit.

Providing a REST API to retrieve the DVR
Providing a REST API to verify ZkPass Proof
REST API
REST API
import { DvrModuleClient, extractPayload } from "@zkpass/dvr-client-ts";

const dvrPayload = extractPayload(dvrToken);
...

// Step 1: Instantiate the zkPassClient object.
const dvrModuleClient = new DvrModuleClient({
      baseUrl: ZKPASS_SERVICE_URL,
      apiKey: API_KEY,
      secretApiKey: API_SECRET,
    });

// Step 2: Create the expected metadata
const expectedMetadata = {
      dvr: JSON.stringify(dvrPayload),
      ttl: EXPECTED_DVR_TTL,
      user_data_verifying_keys: userDataVerifyingKeys,
    };

// Step 3: Call zkPassClient.verifyZkPassProof to verify the proof.
const proofOutput = dvrModuleClient.callDvrVerifyZkPassProof(
      ZKPASS_ZKVM,
      zkPassProofToken,
      expectedMetadata
    );
[
  {
    assign: {
      employee_onboard: {
        and: [
          { "==": [{ dvar: "bcaDocID" }, "DOC897923CP"] },
          { "~==": [{ dvar: "personalInfo.firstName" }, "Ramana"] },
          { "~==": [{ dvar: "personalInfo.lastName" }, "Maharshi"] },
          {
            "~==": [{ dvar: "personalInfo.driverLicenseNumber" }, "DL77108108"],
          },
          {
            ">=": [{ dvar: "financialInfo.creditRatings.pefindo" }, 650],
          },
          {
            ">=": [
              { dvar: "financialInfo.accounts.savings.balance" },
              55000000,
            ],
          },
        ],
      },
    },
  },
  { output: { result: { lvar: "employee_onboard" } } },
]
<query> ::= <boolean-expression>

<boolean-expression> ::= "{" <logical-operator> ": [" <expression-list> "] "}"

<logical-operator> ::= "and" | "or"

<expression-list> ::= <expression> | <expression> "," <expression-list>
<expression> ::= <relational-expression> | <boolean-expression>

<relational-expression> ::= "{" <relational-operator> ": [" <variable> "," <literal> "] "}"

<relational-operator> ::= "==" | "!=" | ">" | ">=" | "<" | "<=" | "~==" | "~!="

<variable> ::= <string>

<literal> ::= <integer> | <string> | <boolean>

<integer> ::= ["-"] <digit>+

<string> ::= """ <characters> """

<boolean> ::= "true" | "false"

<characters> ::= <character>*
<character> ::= <letter> | <digit> | <special-character> | " "

<special-character> ::= "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | "(" | ")" | "-" | "+" | "=" | "[" | "]" | "{" | "}" | "|" | ":" | ";" | "'" | "<" | ">" | "," | "." | "/" | "?" | "~"

<letter> ::= "a" ... "z" | "A" ... "Z"
<digit> ::= "0" ... "9"
[
  {
    assign: {
      account_holder: {
        and: [
          { "==": [{ dvar: "bcaDocID" }, "DOC897923CP"] },
          { "~==": [{ dvar: "personalInfo.firstName" }, "Ramana"] },
          { "~==": [{ dvar: "personalInfo.lastName" }, "Maharshi"] },
          {
            "~==": [{ dvar: "personalInfo.driverLicenseNumber" }, "DL77108108"],
          },
          {
            ">=": [{ dvar: "financialInfo.creditRatings.pefindo" }, 650],
          },
          {
            ">=": [
              { dvar: "financialInfo.accounts.savings.balance" },
              55000000,
            ],
          },
        ],
      },
    },
  },
  { output: { result: { lvar: "account_holder" } } },
]
// Step 1: Instantiate DvrModuleClient
const dvrModuleClient = new DvrModuleClient({
      baseUrl: SERVICE_URL,
      apiKey: API_KEY,
      secretApiKey: API_SECRET,
    });

// Step 2: Call the DVR module client's callDvrGenerateZkPassProof
const zkPassProof = dvrModuleClient.callDvrGenerateZkPassProof(
      JSON.stringify(userDataToken),
      dvrToken
    );
The layering of JWE and JWS on DVR

Rust

This section demonstrates how to use the DVR types to interact with the DVR client binary to:

  1. Generate a DVR token.

  2. Generate a User Data token.

  3. Generate a zkPass proof.

  4. Verify a zkPass proof.

Typescript

This section demonstrates how to use the DVR module client SDK to:

  1. Generate a DVR token.

  2. Generate a User Data token.

  3. Generate a zkPass proof.

  4. Verify a zkPass proof.

Directory Structure

Here's the directory structure for Tyepscript SDK tutorial.

├── src
│    ├── libs
│    │    ├── Holder.ts
│    │    ├── Issuer.ts
│    │    └── Verifier.ts
│    └── utils
│         ├── constants.ts
│         ├── dvrTable.ts
│         └── helper.ts
├── index.ts
├── MyHolder.ts
├── MyIssuer.ts
└── MyVerifier.ts

Components :

  1. MyHoder, MyIssuer, and MyVerifier provide an overview of the process.

  2. The Libs folder contains the detailed implementation of each actor.

  3. The Utils folder includes miscellaneous functions.

REST API
JSON Web Signature (JWS)
JSON Web Encryption (JWE)

Running Code

System Requirements

  1. Ubuntu version 20 or higher WSL (Windows Subsystem for Linux) is also supported. Other similar Linux distros should also work.

  1. Some APT package dependencies Run the following to install the required packages:

sudo apt install build-essential
sudo apt install pkg-config
sudo apt install libssl-dev
  1. Rust compiler toolchain Follow this 2-step instruction to install the Rust toolchain.

# 1: install cargo toolchain
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
# 2: source the cargo env for the first time
source "$HOME/.cargo/env"

Installing the SDK and Run zkpass-demo

Follow these steps to install the zkPass SDK and to run the demo application.

For the purposes of this guide, the zkpass-sdk repository is cloned under the home directory of the current user, retaining its default name. This places the root directory for the zkpass-sdk repository at ~/zkpass-sdk. As a result, the directory for the Rust/Linux binding of the SDK is set at ~/zkpass-sdk/rust.

Should you choose to clone the zkpass-sdk repository into a different location, ensure that you adjust any referenced paths in the instructions to match your chosen directory structure.

  1. Clone the zkpass-sdk repo

git clone https://github.com/gl-zkPass/zkpass-sdk.git
  1. Enter zkpass-sdk/rust Directory

cd zkpass-sdk/rust
  1. From the zkpass-sdk/rust directory, execute test.sh script to build the SDK and run the demo application:

./test.sh

The correct output of zkpass-demo should look like the following:

<== Using Single User Data ==>
#### starting zkpass proof generation...
2024-09-03T07:23:42.591248Z  INFO run_data_holder{zkvm="r0" ... (omitted for clarity) ... >> generate_zkpass_proof
2024-09-03T07:23:42.626726Z  INFO run_data_holder{zkvm="r0" ... (omitted for clarity) ... Fetching public keys from https://playground-zkpass.ssi.id/.well-known/jwks.json
2024-09-03T07:23:48.169443Z  INFO run_data_holder{zkvm="r0" ... (omitted for clarity) ... << generate_zkpass_proof
#### generation completed [time=5.833258046s]

#### starting zkpass proof verification...
2024-09-03T07:23:48.424559Z  INFO run_data_holder{zkvm="r0" ... (omitted for clarity) ... >> verify_zkpass_proof_internal
2024-09-03T07:23:48.461295Z  INFO run_data_holder{zkvm="r0" ... (omitted for clarity) ... Fetching public keys from https://playground-zkpass.ssi.id/.well-known/jwks.json
2024-09-03T07:23:48.729210Z  INFO run_data_holder{zkvm="r0" ... (omitted for clarity) ... >> verify_zkproof
2024-09-03T07:23:48.729437Z  INFO run_data_holder{zkvm="r0" ... (omitted for clarity) ... << verify_zkproof
2024-09-03T07:23:48.732602Z  INFO run_data_holder{zkvm="r0" ... (omitted for clarity) ... << verify_zkpass_proof_internal
#### found dvr: id=868cbebb-9172-4807-846f-7f5bea6d20e3
#### verification completed [time=308.127227ms]
json-result={
  "name": "Dewi",
  "result": true
}
>> output list:
key=name, value=Str("Dewi")
key=result, value=Bool(true)
<< end of list
the query result is true

... (omitted for clarity) ...


<== Using Multiple User Data ==>
#### starting zkpass proof generation...
... (omitted for clarity) ...
#### generation completed [time=5.33967994s]

#### starting zkpass proof verification...
... (omitted for clarity) ...
#### verification completed [time=221.231359ms]
json-result={
  "name": "Dewi",
  "result": true
}
>> output list:
key=name, value=Str("Dewi")
key=result, value=Bool(true)
<< end of list
the query result is true

... (omitted for clarity) ...


<== Using Example ==>
#### starting zkpass proof generation...
... (omitted for clarity) ...
#### generation completed [time=5.55306725s]

#### starting zkpass proof verification...
... (omitted for clarity) ...
#### verification completed [time=288.768931ms]
json-result={
  "title": "Loan Query Results",
  "result": true,
  "name": "Ramana",
  "email": "Ramana.Maharshi@karma.org"
}
>> output list:
key=title, value=Str("Loan Query Results")
key=result, value=Bool(true)
key=name, value=Str("Ramana")
key=email, value=Str("Ramana.Maharshi@karma.org")
<< end of list
the query result is true

Troubleshooting

Fetch Timeout

This demo will download a binary file. If the download process times out, try the following solutions:

  1. Ensure you have a stable internet connection when running the script.

  2. Turn off any active VPNs and try again.

Missing/Corrupt .so Files

The error message "cannot open shared object file: No such file or directory" indicates an issue. This may occur due to missing or corrupted .so. Here are some possible solutions:

  1. Ensure you have a stable internet connection when running the script.

  2. Turn off any active VPNs and try again.

  3. Manually download the .so file:

    1. Move these files to zkpass-sdk/rust/lib folder.

    2. Comment out download-so.sh in test.shscript.

    3. Run the test.sh script again; the error should be resolved.

Running Code

System Requirements

  1. Ubuntu version 20 or higher, WSL (Windows Subsystem for Linux) is also supported.

Make sure the VPN is off

Installing WSL for Windows users

This command will enable the necessary features to run WSL and install the Ubuntu distribution of Linux.

If your underlying system, like Ubuntu, is already Linux-based, you can skip this step.

  1. Open PowerShell or Windows Command Prompt in administrator mode by right-clicking and selecting "Run as administrator"

  2. Run the command below

wsl --install
  1. Restart your machine

  2. Once you have installed WSL, you will need to create a user account and password for your newly installed Linux distribution.

If you have installed WSL before, you can login using the command wsl

Installing Node.js 18.17.0 via NVM

Installing NVM

nvm allows you to quickly install and use different versions of node via the command line.

  1. Run the command below

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
  1. Restart your terminal session

Installing Node 18.17.0 and NPM via NVM

nvm install 18.17.0

To check whether Node has been installed properly, run the commands below:

node -v
npm -v

Installing Git

sudo apt update
sudo apt install git

To check whether Node has been installed properly, run the commands below:

git --version

Installing the SDK

If you wish to explore our demo application, feel free to skip this installation step, as it has already been completed in the demo application.

If you want to use our zkpass-client-ts library on your own project / outside the demo application, you can follow this step

  1. Set the npm registry configuration to gdp-labs registry.

npm config set @zkpass:registry=https://us-west1-npm.pkg.dev/gdp-labs/gdplabs-npm-public/
  1. Install the zkpass-client library for typescript

npm install @zkpass/dvr-client-ts

For NextJS projects with App Routing, several configurations have to be made in next.config.js file:

next.config.js

const nextConfig = {
  ...,
  experimental: {
    ...,
    esmExternals: "loose", // Enable ESM imports
    serverComponentsExternalPackages: ["@zkpass/dvr-client-ts"], // Exclude SDK from bundling, to enable reading binary file
  },
};

module.exports = nextConfig;

Running CLI Demo

Cloning Demo

To try our Typescript CLI demo, you can follow these steps

  1. Clone demo repository

git clone https://github.com/gl-zkPass/zkpass-sdk.git
  1. Go to Typescript CLI demo directory (Let's assume this is our root directory for steps below)

cd zkpass-sdk/typescript/

Running Demo

  1. Install packages

npm install
  1. Run Dewi demo

It will run the demo using predefined user data and DVR for Dewi. The expected query result is "false".

npm run demo-dewi

Expected result :

...
...
#### starting zkpass proof verification...
#### verification completed [time=118ms]
the query result is false
  1. Run Ramana demo

It will run the demo using predefined user data and DVR for Ramana. The expected query result is "true".

npm run demo-ramana

Expected result :

...
...
#### starting zkpass proof verification...
#### verification completed [time=60ms]
the query result is true
  1. Run Jane demo

It will run the demo using predefined user data and DVR for Jane. The expected query result is "true".

npm run demo-jane

Expected result :

...
...
#### starting zkpass proof verification...
#### verification completed [time=46ms]
the query result is true
  1. Run demo with custom data

You can run the demo using custom data. Examples for user data and DVR can be found in rust/test/data.

Example running demo using custom data :

npm run demo ../rust/test/data/basic-data.json ../rust/test/data/basic-dvr.json

Expected result :

...
...
#### starting zkpass proof verification...
#### verification completed [time=51ms]
the query result is true
  1. Run demo with multiple user data

You can also run the demo using multiple user data. Examples for multiple user data and DVR can be found in typescript/test/data/multiple.

Example running demo using multiple data:

npm run demo-multi

Directory Structure

Here's the directory structure for Rust SDK tutorial.

The privacy-apps components :

  1. DVR types provide the necessary definitions for developers to interact with libdvr_client.so.

  2. Client utils contain FFI helpers for working with DVR types.

The zkpass-demo components :

  1. data_holder.rs: Handles the entire process, from generating tokens to verifying proofs.

  2. data_issuer.rs: Manages the process of generating user data tokens.

  3. proof_verifier.rs: Handles the generation of DVR tokens and the proof verification process.

  4. lib_loader.rs: Contains the detailed logic for interacting with libdvr_client.so.

Typescript

Table of contents

Classes

Functions

Interfaces

Type Aliases

Constants

Errors

Functions: ffiHelper

Helper functions for transforming data into FFI-compatible format

Table of contents

Functions

Functions

transformPublicKeyOrKeysetToFfi

Parameters

Returns

object - The FFI equivalent of the provided PublicKeyOrKeysetEndpoint

Throws

  • Error if PublicKeyOrKeysetEndpoint is missing required fields

  • Error if PublicKeyOrKeysetEndpoint has an invalid type


transformDvrDataToFfi

Parameters

Returns

object - A new instance of DvrDataFfi containing the transformed data

Throws

  • Error if user_data_requests is empty


transformExpectedDvrMetadataToFfi

Parameters

Returns

object - An FFI equivalent of the input metadata

Throws

  • Error if metadata.user_data_verifying_keys is empty

DVR Workflows

The DVR app distinguishes itself with its adaptable workflows, specifically tailored to suit different business contexts. The platform supports two primary workflows: Holder-Centric, ideal for B2C (Business-to-Client) scenarios, and Verifier-Centric, suited for B2B (Business-to-Business) environments. Understanding how these workflows operate and their applicability can greatly enhance the effectiveness of DVR in various settings.

Holder-Centric Workflow

In a B2C setting, where businesses interact directly with individual clients or customers, the Holder-Centric workflow is particularly effective. Here, the Data Holder (the client or customer) initiates the data verification process by requesting a Data Verification Request (DVR) from the Proof Verifier. This approach empowers the individual, allowing them to control how and when their data is verified, aligning perfectly with customer-centric business models where individual agency and privacy are paramount.

Verifier-Centric Workflow

Conversely, in a B2B context, the Verifier-Centric workflow becomes more relevant. In this model, the verification process starts with the Proof Verifier, usually a business, sending the DVR directly to the Data Issuer. This workflow is suitable for situations where businesses need to establish or verify partnerships, credentials, or compliance among other businesses. The verifier-centric approach offers a streamlined and efficient method for regular or systematic verifications, which is common in business-to-business interactions.

DVR's capability to support both holder-centric and verifier-centric workflows provides a significant advantage in catering to a wide range of customer needs. Whether it’s a business dealing with individual clients or other businesses, DVR offers a tailored approach to data verification. This flexibility ensures that the platform is not only versatile but also highly relevant and efficient in various real-world applications.

In summary, the dual workflow approach of DVR – holder-centric for B2C and verifier-centric for B2B – showcases the platform's versatility and adaptability to different business models. By understanding and utilizing these workflows appropriately, organizations can maximize the benefits of DVR, ensuring a seamless, secure, and user-friendly experience in their data verification processes.

Code Snippet

This section describes how we use the zkPass SDK in our demo code

Generate Proof

This code snippet generates a zkPass proof. It requires 3 parameters:

  1. SERVICE_URL : you can use https://playground-zkpass.ssi.id , or use your own endpoint if you deploy zkPass on your own server.

  2. API_KEY & API_SECRET: Get yours at https://portal.ssi.id

Verify Proof

This code snippet verifies a zkPass proof token. Components :

  1. expectedMetadata : this is the expected metadata of the dvr.

  2. dvrPayload: the dvr payload extracted from Dvr token.

Generate User Data Token

This code snippet generate user data token. Components :

  1. signingKey : a private key used to sign user data.

  2. data : user data in JSON format.

Generate DVR Token

This code snippet generate DVR token. Components :

  1. signingKey : a private key used to sign dvr.

  2. dvrData : Dvr data to sign.

For WSL installation guide, .

Download file from the website.

To install the Dvr Module Client lib separately, please refer to this section

or later.

If your Windows version is below Windows 10 2004, please refer to instead.

The above command only works if WSL is not installed at all, if you run wsl --install and see the WSL help text, please try running wsl --list --online to see a list of available distros and run wsl --install -d <DistroName> to install a distro. To uninstall WSL, see or .

For a complete WSL installation guide, refer to .

Complete NVM documentation can be found .

Complete Git documentation can be found .

The serverComponentsExternalPackages configuration ensures that the package @zkpass/dvr-client-ts is excluded from NextJS' bundling and compilation process, allowing it to be imported directly from node_modules. As a result, remember to include the node_modules directory in your production build. See .

The demo application will run in a CLI and requires 2 parameters: DVR and user data. Please review to have better understanding of the use case.

▸ transformPublicKeyOrKeysetToFfi(value: ): object

Name
Type
Description

▸ transformDvrDataToFfi(data: ): object

Name
Type
Description

▸ transformExpectedDvrMetadataToFfi(metadata: ): object

Name
Type
Description

userDataToken : check section for more details.

dvrToken : check section for more details.

zkPassProofToken : check section for more details.

read here
libdvr_client.so
Node.js 18.17.0
Git
this documentation
Uninstall legacy version of WSL
unregister or uninstall a Linux distribution
this documentation
here
here
NextJS Deployment Guide
zkPass key concepts
Installing the Dvr Module Client lib
├── Cargo.lock
├── cargo-test.sh
├── Cargo.toml
├── download-so.sh
├── generate-docs.sh
├── lib
│   └── libdvr_client.so
├── localization
│   ├── en-US.ftl
│   └── id-ID.ftl
├── privacy-apps
│   ├── client_utils
│   └── dvr_types
├── README.md
├── rust-toolchain.toml
├── target
│   ├── CACHEDIR.TAG
│   ├── debug
│   ├── release
│   └── tmp
├── test
│   └── data
├── test.sh
├── zkpass-core
│   ├── Cargo.toml
│   └── src
├── zkpass-demo
│   ├── Cargo.toml
│   ├── src
│   ├── test
│   └── tests
└── zkpass-query
    ├── risc0
    ├── sp1
    └── types
zkpass-demo
├── Cargo.toml
├── src
│   ├── data_holder.rs
│   ├── data_issuer.rs
│   ├── helper.rs
│   ├── lib_loader.rs
│   ├── main.rs
│   ├── proof_verifier.rs
│   ├── sample_keys.rs
│   ├── sample_proof.rs
│   └── test.rs
├── test
│   └── data
│       └── multiple
└── tests
    └── integration_test.rs
import { DvrModuleClient } from "@zkpass/dvr-client-ts";

...

// Step 1: Instantiate DvrModuleClient
const dvrModuleClient = new DvrModuleClient({
      baseUrl: SERVICE_URL,
      apiKey: API_KEY,
      secretApiKey: API_SECRET,
    });

// Step 2: Call the DVR module client's callDvrGenerateZkPassProof
const zkPassProof = dvrModuleClient.callDvrGenerateZkPassProof(
      JSON.stringify(userDataToken),
      dvrToken
    );
import { DvrModuleClient, extractPayload } from "@zkpass/dvr-client-ts";

const dvrPayload = extractPayload(dvrToken);
...

// Step 1: Instantiate the zkPassClient object.
const dvrModuleClient = new DvrModuleClient({
      baseUrl: ZKPASS_SERVICE_URL,
      apiKey: API_KEY,
      secretApiKey: API_SECRET,
    });

// Step 2: Create the expected metadata
const expectedMetadata = {
      dvr: JSON.stringify(dvrPayload),
      ttl: EXPECTED_DVR_TTL,
      user_data_verifying_keys: userDataVerifyingKeys,
    };

// Step 3: Call zkPassClient.verifyZkPassProof to verify the proof.
const proofOutput = dvrModuleClient.callDvrVerifyZkPassProof(
      ZKPASS_ZKVM,
      zkPassProofToken,
      expectedMetadata
    );
import { DvrModuleClient } from "@zkpass/dvr-client-ts";

...

// Step 1: Instantiate DvrModuleClient
const dvrModuleClient = new DvrModuleClient({
      baseUrl: SERVICE_URL,
      apiKey: API_KEY,
      secretApiKey: API_SECRET,
    });
//
// Step 2: Call the DVR module client's callDvrGenerateUserDataToken
//         This is to digitally-sign the user data.
const userDataToken = dvrModuleClient.callDvrGenerateUserDataToken(
      signingKey,
      JSON.stringify(data)
    );
import { DvrModuleClient } from "@zkpass/dvr-client-ts";

...

// Step 1: Initiate DvrModuleClient
const dvrModuleClient = new DvrModuleClient({
      baseUrl: SERVICE_URL,
      apiKey: API_KEY,
      secretApiKey: API_SECRET,
    });

// Step 2: Generate Dvr query token
const dvrToken = dvrModuleClient.callDvrGenerateQueryToken(
      signingKey,
      dvrData
    );

RESTful API

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

Building Rust doc

Follow the instructions below to build the Rust doc yourself from the source code.

In this documentation, we refer to the project directory as /home/builder/zkpass-sdk. This path is used as an example that represents the root directory of the clonedzkpass-sdkrepository on your local system. When following these instructions, please substitute /home/builder/zkpass-sdkwith the actual path to your project's root directory.

Generating the Rust doc

To generate the zkpass-client lib documentation locally, do the following:

cd ~/zkpass-sdk/rust
cargo doc -p dvr_types --no-deps --open

After completing these steps, the documentation will automatically open on a browser or you can find the generated documentation in the ~/rust/target/doc directory within the crate's source code directory.

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).

Endpoints

This section provides a detailed reference for all zkPass API endpoints

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.

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 });
  ...
}

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.

{
  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'
}

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

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

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

ZKP

Zero Knowledge Proof

ZKP, or Zero-Knowledge Proof, is a cryptographic method that allows one party to prove to another that a statement is true without revealing any specific information about the statement itself. In the context of verifiable computing, ZKP can be utilized to verify that computations were executed correctly on a binary app without actually having to re-execute or inspect the computation in detail. This means that even if a malevolent actor attempts to hack or tamper with the binary app's execution, they cannot falsify the ZKP. This is because the proof generated is mathematically bound to the correctness of the computation; any deviation from the correct execution would result in a proof that fails to verify. Therefore, using ZKP ensures that the computational results can be trusted without compromising privacy or revealing underlying data.

Imagine you have a magic box that can solve puzzles. You give a friend a puzzle to put inside the box. The box then spits out a "solved" ticket if it successfully solves the puzzle. Zero-Knowledge Proof (ZKP) is like this magic box. It can prove that a computer program did its job correctly without revealing what the job was or how it was done. So, even if someone tries to trick the magic box, they can't fake the "solved" ticket. In this way, you can trust the box's answer without knowing all its secrets.

@zkpass/dvr-client-ts
DvrModuleClient
ffiHelper
jwtHelper
publicKeyOptionUtils
Interfaces
Types
ffiType
Constants
Enums
Errors
Generate User Data Token
Generate DVR Token
Generate Proof
transformPublicKeyOrKeysetToFfi
transformDvrDataToFfi
transformExpectedDvrMetadataToFfi
DvrData
ExpectedDvrMetadata
PublicKeyOrKeysetEndpoint

value

The value to transform

data

The DVR data to transform

metadata

The metadata to transform

Enums

A collection of enums used in the DVR module

Table of contents

Enums

Enums

PublicKeyOptionType

▸ PublicKeyOptionType: Enum

Enum for public key option types.

Name
Value
Description

PublicKey

0

Indicates a public key option

KeysetEndpoint

1

Indicates a keyset endpoint option

Constants

A collection of constants used in the DVR module

Table of contents

Constants

Constants

INVALID_TOKEN

▸ INVALID_TOKEN: "INVALID_TOKEN"

Constant string representing an invalid token.


INVALID_VERIFY_PROOF

▸ INVALID_VERIFY_PROOF: string

JSON string representing an invalid verify proof error. Below is the content of the stringified JSON:

{
  error: "INVALID_VERIFY_PROOF",
}

Types: ffiType

A collection of FFI types used in the DVR module

Table of contents

Types: ffiType

Types: ffiType

FfiResultUserDataToken

▸ FfiResultUserDataToken: StructType A structure representing the result of a user data token operation.

Parameters:

Name
Type
Description

result

ref.refType(ref.types.CString)

The operation result

error

ref.types.CString

Error message if any


FfiResultDvrToken

▸ FfiResultDvrToken: StructType A structure representing the result of a DVR token operation.

Parameters:

Name
Type
Description

result

ref.refType(ref.types.CString)

The operation result

error

ref.types.CString

Error message if any


FfiResultZkPassProofToken

▸ FfiResultZkPassProofToken: StructType A structure representing the result of a zkPass proof token operation.

Parameters:

Name
Type
Description

result

ref.refType(ref.types.CString)

The operation result

error

ref.types.CString

Error message if any


FfiResultVerifyZkPassProofToken

▸ FfiResultVerifyZkPassProofToken: StructType A structure representing the result of a zkPass proof verification token operation.

Parameters:

Name
Type
Description

result

ref.refType(ref.types.CString)

The operation result

error

ref.types.CString

Error message if any


PublicKeyFfi

▸ PublicKeyFfi: StructType A structure representing a public key.

Parameters:

Name
Type
Description

x

ref.types.CString

X coordinate of the public key

y

ref.types.CString

Y coordinate of the public key


KeysetEndpointFfi

▸ KeysetEndpointFfi: StructType A structure representing a keyset endpoint.

Parameters:

Name
Type
Description

jku

ref.types.CString

JSON Web Key Set URL

kid

ref.types.CString

Key identifier


PublicKeyOptionUnionFfi

▸ PublicKeyOptionUnionFfi: StructType A structure representing a union of public key and keyset endpoint.

Parameters:

Name
Type
Description

public_key

The public key structure

keyset_endpoint

The keyset endpoint structure


PublicKeyOptionFfi

▸ PublicKeyOptionFfi: StructType A structure representing a public key option with tag and value.

Parameters:

Name
Type
Description

tag

ref.types.uint64

Type identifier

value

The key data


UserDataRequestFfi

▸ UserDataRequestFfi: StructType A structure representing a user data request.

Parameters:

Name
Type
Description

key

ref.types.CString

Request key

value

Request value


DvrDataFfi

▸ DvrDataFfi: StructType A structure representing DVR data.

Parameters:

Name
Type
Description

zkvm

ref.types.CString

ZKVM identifier

dvr_title

ref.types.CString

DVR title

dvr_id

ref.types.CString

DVR identifier

query

ref.types.CString

Query string

user_data_requests

Array of user data requests

user_data_requests_len

ref.types.uint64

Length of user data requests array

dvr_verifying_key

DVR verifying key


ExpectedDvrMetadataFfi

▸ ExpectedDvrMetadataFfi: StructType A structure representing expected DVR metadata.

Parameters:

Name
Type
Description

ttl

ref.types.uint64

Time to live

dvr

ref.types.CString

DVR data token

user_data_verifying_keys

Array of verifying keys

user_data_verifying_keys_len

ref.types.uint64

Length of verifying keys array

UserDataRequestArrayFfi


UserDataVerifyingKeysFfi

Interfaces

A collection of interfaces used in the DVR module

Table of contents

Interfaces

Interfaces

PublicKey

▸ PublicKey: Object

Represents a public key with x and y coordinates.

Name
Type
Description

x

string

X coordinate of the public key

y

string

Y coordinate of the public key


KeysetEndpoint

▸ KeysetEndpoint: Object

Represents a keyset endpoint configuration.

Name
Type
Description

jku

string

JSON Web Key Set URL

kid

string

Key identifier


PublicKeyOptionUnion

▸ PublicKeyOptionUnion: Object

Union of possible public key options.

Name
Type
Description

keyset_endpoint?

Optional keyset endpoint

public_key?

Optional public key


PublicKeyOption

▸ PublicKeyOption: Object

Configuration for public key options.

Name
Type
Description

tag

Type of the public key option

value

Value of the public key option


UserDataRequest

▸ UserDataRequest: Object

Request format for user data.

Name
Type
Description

key

string

Key for the user data

value

Verifying key or endpoint


DvrData

▸ DvrData: Object

Data structure for DVR operations.

Name
Type
Description

zkvm

string

ZK Virtual Machine identifier

dvr_title

string

Title of the DVR

dvr_id

string

Identifier of the DVR

query

string

Query string

user_data_requests

Array of user data requests

dvr_verifying_key

Key for verifying DVR


DvrDataPayload

▸ DvrDataPayload: Object

Payload format for DVR data.

Name
Type
Description

zkvm

string

ZK Virtual Machine identifier

dvr_title

string

Title of the DVR

dvr_id

string

Identifier of the DVR

query

string

Query string

query_engine_ver

string

Query engine version

query_method_ver

string

Query method version

user_data_requests

object

User data requests

dvr_verifying_key

object

Key for verifying DVR


ExpectedDvrMetadata

▸ ExpectedDvrMetadata: Object

Expected metadata for DVR operations.

Name
Type
Description

ttl

number

Time to live

dvr

string

DVR string

user_data_verifying_keys

Array of user data verifying keys

Rust

Errors

A collection of error codes reference for the DVR module

Error Messages

The following table lists all error messages used across the DVR client modules:

Functions: jwtHelper

Helper functions for extracting and validating JWT payloads

Table of contents

Functions: jwtHelper

Functions: jwtHelper

extractPayload

Extracts the payload from a JWT token and validates its type.

Parameters

Name
Type
Description

token

string

The JWT token to extract payload from

Returns

Throws

  • Error if token is invalid

  • Error if payload is not of type DvrData


extractZkProofPayload

Extracts the ZkPassProof payload from a JWT token.

Parameters

Name
Type
Description

token

string

The JWT token containing zkPass proof

Returns

ZkPassProof - The extracted zkPass proof object

Throws

  • Error if token is invalid

  • Error if payload is not of type ZkPassProof


decodeJwtPayload

▸ private decodeJwtPayload(token: string): any

Parameters

Name
Type
Description

token

string

The JWT token to decode

Returns

any - The parsed payload from the JWT token

Throws

  • Error if token is invalid


isZkPassProof

▸ private isZkPassProof(data: any): boolean

Parameters

Name
Type
Description

data

any

The data to check

Returns

boolean - True if data is a valid ZkPassProof


isDvrData

▸ private isDvrData(data: any): boolean

Parameters

Name
Type
Description

data

any

The data to check

Returns

boolean - True if data is a valid DvrDataPayload

Overview

Prerequisites

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

  1. User Data Token

  2. 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!

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?

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:

Code Snippet

This section describes how we use the zkPass SDK in our demo code

Generate Proof

use crate::lib_loader::generate_zkpass_proof;

let zkpass_proof_token = unsafe {
    generate_zkpass_proof(credentials, user_data_tokens, dvr_token)
};

This code snippet generates a zkPass proof. It requires 3 parameters:

  1. credentials : Get yours API key and secret at https://portal.ssi.id

  2. user_data_tokens : stringified signed users data.

  3. dvr_token : signed Dvr query.

Verify Proof

use crate::lib_loader::verify_zkpass_proof;
use dvr_types::ExpectedDvrMetadataFfi;

//
// Step 1: Create the expected metadata object.
//
let expected_metadata = ExpectedDvrMetadataFfi {
    ttl: some_ttl,
    dvr: expected_dvr_cstring.as_ptr(),
    user_data_verifying_keys: user_data_requests_slice.as_ptr(),
    user_data_verifying_keys_len: user_data_requests_slice.len() as u64,
};

//
// Step 2: Call verify proof.
//
let result = unsafe {
    verify_zkpass_proof(&service_url, zkvm, zkpass_proof_token, expected_metadata)
};

This code snippet verifies a zkPass proof token. Components :

  1. expected_metadata : this is the expected metadata of the dvr.

  2. zkvm: zkvm used to generate proof, currently we only support r0.

  3. service_url : you can use https://playground-zkpass.ssi.id , or use your own endpoint if you deploy zkPass on your own server.

Generate User Data Token

use crate::lib_loader::generate_user_data_token;

let user_data_token = unsafe {
    generate_user_data_token(signing_key, &data.to_string())
};

This code snippet generate user data token. Components :

  1. signing_key : a private key used to sign user data.

  2. data : user data in JSON format.

Generate DVR Token

use crate::lib_loader::generate_query_token;

let dvr_token = unsafe { generate_query_token(signing_key, dvr_data) };

This code snippet generate DVR token. Components :

  1. signing_key : a private key used to sign dvr.

  2. dvr_data : Dvr data to sign.

Functions: publicKeyOptionUtils

A collection of utility functions for converting between PublicKey and KeysetEndpoint

Table of contents

Functions

Functions

convertToPublicKeyOption

Converts a PublicKey or KeysetEndpoint object into a PublicKeyOption structure.

Parameters

Returns

Throws

  • Error if input is neither a valid PublicKey nor KeysetEndpoint

Types

A collection of types used in the DVR module

Table of contents

Types

Types

PublicKeyOrKeysetEndpoint

A union type that can either be a PublicKey or KeysetEndpoint.


ZkPassOutput

▸ ZkPassOutput: { [key: string]: string | number | boolean }

Key-value pairs representing the output data from a zkPass operation.


ZkPassProof

▸ ZkPassProof: Object

Properties representing a zkPass proof.

Name
Type
Description

zkproof

string

The zkPass proof string

dvr_title

string

Title of the DVR

dvr_id

string

Identifier of the DVR

dvr_digest

string

Digest of the DVR

user_data_verifying_keys

object

Keys used for verifying user data

dvr_verifying_key

object

Key used for verifying DVR

time_stamp

number

Timestamp of the proof generation


VerifyZkPassProofResult

▸ VerifyZkPassProofResult: Object

Result of verifying a zkPass proof.

Name
Type
Description

output

The output data

zkpass_proof

The zkPass proof data

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:

Endpoint

Type
Value

HTTP Method

POST

API endpoint (Playground)

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

Request Header

Authorization: Basic [apiToken]
Content-Type: application/json
Parameter
Description

Authorization

base64 form of YOUR_API_KEY:YOUR_API_SECRET

Content-Type

Indicates that the content being sent or received is JSON data

Request Body

{
    "user_data_token": "[encryptedUserDataToken]",
    "dvr_token": "[encryptedDvrToken]"
}
Parameter
Type
Mandatory
Description

user_data_token

string

Mandatory

encrypted user data token in JWE format

dvr_token

string

Mandatory

encrypted dvr token in JWE format

Response

{
    "status": 200,
    "proof": "eyJ0e..."
}

DVR

Data Verification Request

Data Verification Request (DVR) is the main application in the zkPass framework. It contains a query that serves as the criteria against which user data is verified. Created by the Proof Verifier, DVR Query works as conditional statements applied to relevant fields in the user data. These queries enable the Proof Verifier to validate user information without having the Data Holder expose the user's sensitive content.

Sign User Data and DVR

Prerequisites

Make sure you have key pair consisting of :

  1. publicKeyJWKS

  2. privateKey

Overview

Example Implementation

JWKS

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

{
  "keys": [
    {
      "x": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELOmrNI4A9ML4iGJXpYlaZiYGVCxB",
      "y": "k+evjhOZEbCLj17o/ZdfEv7dUZIRKRoZ1bud5Gq8OCItDlXkTyMrtWrhdA==",
      "kid": "q6ZFSOJcTiZWJWkvUshpFw5v20xstZN/T4lt4zpKsUg="
    }
  ]
}

JWS

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

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);
  }

Example for User Data

{
  "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
  }
}

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

[
  {
    "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" } } }
]

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

{
  "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"
  }
}

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.

{
  "userDataToken": "eyJ0eXAiOiJKV1QiLCJqa3UiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZ2wtemtQYXNzL3prcGFzcy1zZGsvbWFpbi9kb2NzL3prcGFzcy9zYW1wbGUtandrcy9pc3N1ZXIta2V5Lmpzb24iLCJraWQiOiJrLTEiLCJhbGciOiJFUzI1NiJ9.eyJkYXRhIjp7InRlc3RJRCI6IlNDUkVFTi03MDgzLTEyMzQ1IiwidGVzdE5hbWUiOiJRdWFsaXR5SGVhbHRoIENvbXByZWhlbnNpdmUgU2NyZWVuIiwidGVzdERhdGUiOiIyMDIzLTA4LTI3VDE0OjAwOjAwWiIsImxhYiI6eyJuYW1lIjoiUXVhbGl0eUhlYWx0aCBMYWJzIiwiSUQiOiJRSDgwMTg3NCIsImFkZHJlc3MiOiIxMjM0IEVsbSBTdCwgT2FrbGFuZCwgVVNBIn0sInN1YmplY3QiOnsiZmlyc3ROYW1lIjoiSmFuZSIsIl9maXJzdE5hbWVfemtwYXNzX3B1YmxpY18iOnRydWUsImxhc3ROYW1lIjoiRG9lIiwiZGF0ZU9mQmlydGgiOiIxOTg1LTEyLTEyIiwiYmxvb2RUeXBlIjoiQSsiLCJETkFJbmZvIjp7Im1hcmtlcnMiOnsiQVBPRSI6WyJFMyIsIkUzIl0sIkJSQ0ExIjoiTm9ybWFsIiwiTVRIRlIiOlsiQzY3N1QiLCJBMTI5OEMiXX0sImhhcGxvZ3JvdXBzIjp7InBhdGVybmFsIjoiUjFiMSIsIm1hdGVybmFsIjoiSDFhMSJ9fSwiY29udGFjdCI6eyJlbWFpbCI6ImphbmUuZG9lQGdtYWlsLmNvbSIsIl9lbWFpbF96a3Bhc3NfcHVibGljXyI6dHJ1ZSwicGhvbmUiOiI2NTAtNTU1LTEyMzQifSwiYWRkcmVzcyI6eyJzdHJlZXQiOiI3ODkgT2FrIFN0cmVldCIsImNpdHkiOiJTYW4gSm9zZSIsInN0YXRlIjoiQ0EiLCJ6aXAiOiI5NTEzNCJ9fSwibWVhc3VyZWRQYW5lbHNOZ01MIjp7ImFtcGhldGFtaW5lcyI6MCwiY29jYWluZSI6OCwib3BpYXRlcyI6MTAyLCJiZW56b2RpYXplcGluZXMiOjB9fX0.TwoIFlHXnKjhKGlhW6tCfuc20pgvFFUmZ_wEMBvrQyKaub7aN3SBT0_zPPeDn_EUi2UP6eo0pr7ofNjfXEtgsA",
  "dvrToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJkYXRhIjp7Inprdm0iOiJyMCIsImR2cl90aXRsZSI6Ik15IERWUiIsImR2cl9pZCI6ImQ1YmJhOWRjLWU5MGMtNDU2ZC04MTFjLTc5YWE3Mzc1NWY1NCIsInF1ZXJ5IjoiW3tcImFzc2lnblwiOntcImJsb29kX3Rlc3Rfc3RhdHVzXCI6e1wiYW5kXCI6W3tcIj09XCI6W3tcImR2YXJcIjpcImxhYi5JRFwifSxcIlFIODAxODc0XCJdfSx7XCI9PVwiOlt7XCJkdmFyXCI6XCJ0ZXN0SURcIn0sXCJTQ1JFRU4tNzA4My0xMjM0NVwiXX0se1wifj09XCI6W3tcImR2YXJcIjpcInN1YmplY3QuZmlyc3ROYW1lXCJ9LFwiamFuZVwiXX0se1wifj09XCI6W3tcImR2YXJcIjpcInN1YmplY3QubGFzdE5hbWVcIn0sXCJkb2VcIl19LHtcIj09XCI6W3tcImR2YXJcIjpcInN1YmplY3QuZGF0ZU9mQmlydGhcIn0sXCIxOTg1LTEyLTEyXCJdfSx7XCI9PVwiOlt7XCJkdmFyXCI6XCJzdWJqZWN0LmNvbnRhY3QuZW1haWxcIn0sXCJqYW5lLmRvZUBnbWFpbC5jb21cIl19LHtcIj09XCI6W3tcImR2YXJcIjpcIm1lYXN1cmVkUGFuZWxzTmdNTC5hbXBoZXRhbWluZXNcIn0sMF19LHtcIjw9XCI6W3tcImR2YXJcIjpcIm1lYXN1cmVkUGFuZWxzTmdNTC5jb2NhaW5lXCJ9LDEwXX1dfX19LHtcIm91dHB1dFwiOntcIm5hbWVcIjp7XCJkdmFyXCI6XCJzdWJqZWN0LmZpcnN0TmFtZVwifX19LHtcIm91dHB1dFwiOntcImVtYWlsXCI6e1wiZHZhclwiOlwic3ViamVjdC5jb250YWN0LmVtYWlsXCJ9fX0se1wib3V0cHV0XCI6e1wicmVzdWx0XCI6e1wibHZhclwiOlwiYmxvb2RfdGVzdF9zdGF0dXNcIn19fV0iLCJxdWVyeV9lbmdpbmVfdmVyIjoiMS4zLjAiLCJxdWVyeV9tZXRob2RfdmVyIjoiMjQ1NTVmZTE2M2U1MjNiYjMxM2RmODM1NWNhMzlmYmQ3OWQ0OWEwMmM2NDIzNzNiMTljMmEzMWNmYzdhNzhkIiwidXNlcl9kYXRhX3JlcXVlc3RzIjp7IiI6eyJ1c2VyX2RhdGFfdXJsIjpudWxsLCJ1c2VyX2RhdGFfdmVyaWZ5aW5nX2tleSI6eyJLZXlzZXRFbmRwb2ludCI6eyJqa3UiOiJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZ2wtemtQYXNzL3prcGFzcy1zZGsvbWFpbi9kb2NzL3prcGFzcy9zYW1wbGUtandrcy9pc3N1ZXIta2V5Lmpzb24iLCJraWQiOiJrLTEifX19fSwiZHZyX3ZlcmlmeWluZ19rZXkiOnsiS2V5c2V0RW5kcG9pbnQiOnsiamt1IjoiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2dsLXprUGFzcy96a3Bhc3Mtc2RrL21haW4vZG9jcy96a3Bhc3Mvc2FtcGxlLWp3a3MvdmVyaWZpZXIta2V5Lmpzb24iLCJraWQiOiJrLTEifX19fQ.3sGHmQZ_lbEJei9OKTxlshDoYs2wWurjEyiA767BEBrxU5u5fSV-s1qHghVlp748MqZf_cLb7j6g3MrsL34wbw"
}

Encrypt User Data and DVR

Prerequisites

Make sure you have :

  1. userDataToken

  2. dvrToken

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

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);
  }

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

{
  "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"
}

User Data

User Data encapsulates a spectrum of sensitive and confidential attributes, ranging from governmental identification forms like driver's licenses and passports to bank accounts.

In the DVR model, this data is owned by the Data Holder (the user) but provisioned by an entity known as the Data Issuer.

Notably, the DVR and zkPass framework accommodates a high degree of data schematization flexibility. It is engineered to be agnostic to any particular data schema, seamlessly interfacing with JSON objects or any other structured format specified by the Data Issuer. The eventual consumer of the data user is the DVR app running on the zkPass Service.

Class: DvrModuleClient

Client class for the DVR module, accessing the DVR module functions

Table of contents

Constructors

Properties

Methods

Constructors

constructor

  • new DvrModuleClient(config): DvrModuleClient

Constructs a new instance of the DvrModuleClient.

Parameters

Returns

Properties

credentials

  • private credentials: PrivacyAppCredentialsStruct

The credentials structure containing authentication details for the Privacy App Client, including base URL, API key, and secret API key.


library

The loaded library instance containing the foreign function interface (FFI) definitions for DVR module functions.


PACKAGE_NAME

  • private PACKAGE_NAME: "@zkpass/dvr-client-ts" : string

The NPM package name for the DVR client TypeScript library.


LIBRARY_NAME

  • private LIBRARY_NAME: "libdvr_client.so" : string

The name of the shared library file that contains the DVR client implementation.

Methods

loadLibrary

▸ private loadLibrary(): Object

Loads the specified library and defines the foreign function interface (FFI) for the DVR module.

Returns

Object - An object representing the loaded library with the defined FFI functions

The following functions are defined in the FFI:

  • dvr_generate_user_data_token

  • dvr_generate_query_token

  • dvr_generate_zkpass_proof

  • dvr_verify_zkpass_proof


callDvrGenerateUserDataToken

▸ callDvrGenerateUserDataToken(signingKey, stringifiedUserData, verifyingKeyOptionParam): string

Generates a user data JWS token using the provided signing key, user data, and public key option.

Parameters

Returns

string - The generated user data token, or throws an error if generation fails


callDvrGenerateQueryToken

▸ callDvrGenerateQueryToken(signingKey, dvrData): string

Generates a DVR query JWS token using the provided signing key and DVR data.

Parameters

Returns

string - The generated DVR query token, or throws an error if generation fails


callDvrGenerateZkPassProof

▸ callDvrGenerateZkPassProof(stringifiedUserDataTokens, dvrtoken): string

Parameters

Returns

string - The generated zkPass proof, or throws an error if generation fails


callDvrVerifyZkPassProof

▸ callDvrVerifyZkPassProof(zkvm, zkPassProofToken, expectedMetaData): VerifyZkPassProofResult

Parameters

Returns

VerifyZkPassProofResult - The output committed into the zkPass proof, and the zkPass proof data

▸ UserDataRequestArrayFfi: ArrayType An array type of structures.

▸ UserDataVerifyingKeysFfi: ArrayType An array type of structures used for verifying keys.

[]

[]

The zkpass-client API Reference is available as .

Module
Error Message
Description

MISSING_PUBLIC_KEY_VALUES

Thrown when a public key option is missing 'x' or 'y' values

MISSING_KEYSET_ENDPOINT_VALUES

Thrown when a keyset endpoint option is missing 'jku' or 'kid' values

INVALID_PUBLIC_KEY_OPTION_TYPE

Thrown when an invalid public key option type is provided

MISSING_USER_DATA_REQUESTS

Thrown when user_data_requests array is empty

MISSING_USER_DATA_VERIFYING_KEYS

Thrown when user_data_verifying_keys array is empty

ERROR_INVALID_PAYLOAD

Thrown when parsed payload is not of type DvrData

ERROR_INVALID_JWT

Thrown when JWT token format is invalid

ERROR_INVALID_ZK_PROOF

Thrown when ZK proof payload format is invalid

INVALID_INPUT

Thrown when input is neither a valid PublicKey nor KeysetEndpoint

INVALID_TOKEN

Constant string representing an invalid token

INVALID_VERIFY_PROOF

JSON string representing an invalid verify proof error

▸ extractPayload(token: string):

- The extracted payload

▸ extractZkProofPayload(token: string):

Register on the to obtain your API and secret keys.

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.

zkpass_proof_token : check section for more details.

▸ convertToPublicKeyOption(item: | ):

Name
Type
Description

item

|

The item to convert

- A structured object containing the tag and value of the public key option

▸ PublicKeyOrKeysetEndpoint: |

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

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

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

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

Please see example of encrypted User Data and DVR .

For a complete definition of the DVR, please follow this .

Read section for detail info.

We need to sign and before sending a request to the zkPass service. This ensures that the payload is not tampered during transport.

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 .

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 .

Read section for detail info.

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".

For a complete definition of the user data, please follow this .

Name
Type
Description

private library: ReturnType<typeof >

Name
Type
Description
Name
Type
Description
Name
Type
Description
Name
Type
Description
Rust doc pages
API Credentials
zkPass portal
form
Generate Key Pair
Sign User Data and DVR
Encrypt User Data and DVR
Utilities
Generating a Key Pair
Signing User Data and DVR
Encrypting User Data and DVR
link
Generate Key Pair
User Data
Data Verification Request (DVR)
here
here
Sign User Data and DVR
https://playground-zkpass.ssi.id/.well-known/jwks.json
link
PublicKeyOrKeysetEndpoint
ZkPassProof
PublicKeyOrKeysetEndpoint
ZkPassOutput
ZkPassProof
VerifyZkPassProofResult
DvrData
ExpectedDvrMetadata
PublicKey
KeysetEndpoint
PublicKeyOptionUnion
PublicKeyOption
UserDataRequest
DvrData
DvrDataPayload
ExpectedDvrMetadata
DvrDataPayload
DvrDataPayload
PublicKey
KeysetEndpoint
PublicKeyOption
PublicKeyOption
PublicKey
KeysetEndpoint
PublicKeyOptionType
INVALID_TOKEN
INVALID_VERIFY_PROOF
FfiResultUserDataToken
FfiResultDvrToken
FfiResultZkPassProofToken
FfiResultVerifyZkPassProofToken
PublicKeyFfi
KeysetEndpointFfi
PublicKeyOptionUnionFfi
PublicKeyOptionFfi
UserDataRequestFfi
DvrDataFfi
ExpectedDvrMetadataFfi
UserDataRequestArrayFfi
UserDataVerifyingKeysFfi
UserDataRequestFfi
UserDataRequestFfi
extractPayload
extractZkProofPayload
decodeJwtPayload
isZkPassProof
isDvrData
Generate Proof
convertToPublicKeyOption
here

config

PrivacyAppClientConfig

Configuration object

config.baseUrl

string

The base URL for the API

config.apiKey

string

The API key for authentication

config.secretApiKey

string

The secret API key for authentication

signingKey

string

The key used to sign the user data token

stringifiedUserData

string

The user data in stringified format

verifyingKeyOptionParam

PublicKeyOrKeysetEndpoint

The associated key to verify the user data token

signingKey

string

The key used to sign the DVR query

dvrData

DvrData

The data required for generating the DVR query token

stringifiedUserDataTokens

string

Stringified representation of multiple user data tokens using tag as the key

dvrtoken

string

The DVR token to be used in the proof generation

zkvm

string

The zkVM identifier

zkPassProofToken

string

The zkPass proof token to be verified

expectedMetaData

ExpectedDvrMetadata

The expected metadata for the DVR verification

FFI Helpers
FFI Helpers
FFI Helpers
FFI Helpers
FFI Helpers
JWT Helpers
JWT Helpers
JWT Helpers
Public Key Utils
Interface
Interface
DvrModuleClient
PublicKeyFfi
KeysetEndpointFfi
PublicKeyOptionUnionFfi
PublicKeyOptionFfi
UserDataRequestArrayFfi
PublicKeyOptionFfi
UserDataVerifyingKeysFfi
KeysetEndpoint
PublicKey
PublicKeyOptionUnion
UserDataRequest
UserDataRequest
PublicKey
KeysetEndpoint
PublicKeyOptionType
PublicKeyOrKeysetEndpoint
PublicKeyOrKeysetEndpoint
ZkPassOutput
ZkPassProof
constructor
credentials
library
PACKAGE_NAME
LIBRARY_NAME
loadLibrary
callDvrGenerateUserDataToken
callDvrGenerateQueryToken
callDvrGenerateZkPassProof
callDvrVerifyZkPassProof
loadLibrary
https://github.com/gl-zkPass/zkpass-sdk/blob/main/rust/zkpass-demo/src/proof_verifier.rs
/*
 * proof_verifier.rs
 * Simulating the Proof Verifier process for the zkPass Demo
 *
 * ---
 * References:
 *   https://docs.ssi.id/zkpass/zkpass-developers-guide/privacy-apps/dvr/dvr-client-roles/proof-verifier
 * ---
 * Copyright (c) 2024 PT Darta Media Indonesia. All rights reserved.
 */
use crate::{
    helper::extract_payload_without_validation,
    lib_loader::{
        generate_query_token,
        get_dvr_id_from_proof,
        verify_zkpass_proof as verify_zkpass_proof_ffi,
    },
    sample_keys::{ issuer_pubkey, verifier_pubkey, VERIFIER_PRIVKEY },
};
use dvr_types::{
    DvrDataFfi,
    ExpectedDvrMetadataFfi,
    UserDataRequestFfi,
    PublicKeyOptionFfi,
    PublicKeyOptionTagFfi,
    PublicKeyOptionUnionFfi,
    KeysetEndpointFfi,
    PublicKeyFfi,
};
use lazy_static::lazy_static;
use serde_json::Value;
use std::{ collections::HashMap, io::prelude::*, sync::Mutex, time::Instant, ffi::CString };
use tracing::trace;
use uuid::Uuid;

//
//  Global table to store the generated DVR values
//  The Verifier needs to keep track of all generated DVRs
//  so that it can verify the proof metadata
//  Note: The hash table entry should have time-expiration
//
lazy_static! {
    static ref DVR_TABLE: Mutex<HashMap<String, String>> = {
        let map = HashMap::new();
        Mutex::new(map)
    };
}

// This struct ensures that the data reference is valid
pub struct PublicKeyOptionHolder {
    key_x: CString,
    key_y: CString,
    empty_str: CString,
    pub public_key_option: PublicKeyOptionFfi,
}

// This struct ensures that the data reference is valid
#[allow(dead_code)]
struct UserDataRequestsHolder {
    tags: Vec<CString>,
    user_data_requests: Vec<UserDataRequestFfi>,
    key_x: CString,
    key_y: CString,
    empty_str: CString,
    public_key_option: PublicKeyOptionFfi,
}

//
//  Simulating the Proof Verifier
//
pub struct ProofVerifier {
    pub user_data_tags: Vec<String>,
}

impl Default for ProofVerifier {
    fn default() -> Self {
        ProofVerifier {
            user_data_tags: Vec::new(),
        }
    }
}

impl ProofVerifier {
    ///
    /// Generates the user data requests.
    ///
    fn user_data_requests(&self) -> Box<UserDataRequestsHolder> {
        let issuer_public_key_option_holder = self.generate_issuer_public_key_option();
        let user_data_tags = self.user_data_tags.clone();
        let tags: Vec<CString> = user_data_tags
            .iter()
            .map(|tag| CString::new(tag.as_str()).unwrap())
            .collect();

        let user_data_requests = tags
            .iter()
            .map(|tag| {
                UserDataRequestFfi {
                    key: tag.as_ptr(),
                    value: issuer_public_key_option_holder.public_key_option.clone(),
                }
            })
            .collect();

        Box::new(UserDataRequestsHolder {
            tags,
            user_data_requests: user_data_requests,
            key_x: issuer_public_key_option_holder.key_x,
            key_y: issuer_public_key_option_holder.key_y,
            empty_str: issuer_public_key_option_holder.empty_str,
            public_key_option: issuer_public_key_option_holder.public_key_option,
        })
    }

    ///
    /// Simulates the Proof Verifier's get_dvr_token REST API.
    ///
    pub fn get_dvr_token(
        &mut self,
        zkvm: &str,
        dvr_file: &str,
        user_data_tags: Vec<&String>
    ) -> String {
        self.user_data_tags = user_data_tags
            .iter()
            .cloned()
            .map(|s| s.clone())
            .collect();

        let mut query_content = std::fs::File::open(dvr_file).expect("Cannot find the dvr file");
        let mut query = String::new();
        query_content.read_to_string(&mut query).expect("Should not have I/O errors");
        trace!("query={}", query);

        let query: Value = serde_json::from_str(&query).unwrap();

        //
        //  Proof Verifier's integration points with the zkpass-client SDK library
        //  (for get_dvr_token REST API)
        //

        let query_string = serde_json::to_string(&query).unwrap();

        let zkvm_cstring = CString::new(zkvm).unwrap();
        let dvr_title_cstring = CString::new("My DVR").unwrap();
        let dvr_id_cstring = CString::new(Uuid::new_v4().to_string()).unwrap();
        let query_cstring = CString::new(query_string).unwrap();

        let verifier_public_key_option_holder = self.generate_verifier_public_key_option();
        let verifier_public_key_option = verifier_public_key_option_holder.public_key_option;

        let user_data_requests_holder = self.user_data_requests();
        let user_data_requests = user_data_requests_holder.user_data_requests;
        let user_data_requests_slice = user_data_requests.as_slice();

        //
        // Step 1: Create the DVR object.
        //
        let dvr_data = DvrDataFfi {
            zkvm: zkvm_cstring.as_ptr(),
            dvr_title: dvr_title_cstring.as_ptr(),
            dvr_id: dvr_id_cstring.as_ptr(),
            query: query_cstring.as_ptr(),
            user_data_requests: user_data_requests_slice.as_ptr(),
            user_data_requests_len: user_data_requests_slice.len() as u64,
            dvr_verifying_key: verifier_public_key_option,
        };

        //
        //  Step 2: Call dvr client's generate_query_token function
        //          to digitally-sign the dvr data.
        //
        let dvr_token = unsafe { generate_query_token(VERIFIER_PRIVKEY, dvr_data) };
        let payload = extract_payload_without_validation(&dvr_token).unwrap();

        // save the dvr to a global hash table
        // this will be needed by the validator to check the proof metadata
        let mut dvr_table = DVR_TABLE.lock().unwrap();
        if let Some(data) = payload.get("data") {
            let dvr_id = data["dvr_id"].as_str().unwrap();
            dvr_table.insert(dvr_id.to_string(), data.to_string());
        }

        dvr_token
    }

    ///
    /// Generates the public key option.
    ///
    pub fn generate_public_key_option(&self, is_verifier: bool) -> Box<PublicKeyOptionHolder> {
        let (key_x, key_y) = if is_verifier { verifier_pubkey() } else { issuer_pubkey() };
        let key_x = CString::new(key_x).unwrap();
        let key_y = CString::new(key_y).unwrap();
        let empty_str = CString::new("").unwrap();

        let public_key_option = PublicKeyOptionFfi {
            tag: PublicKeyOptionTagFfi::PublicKey,
            value: PublicKeyOptionUnionFfi {
                keyset_endpoint: KeysetEndpointFfi {
                    jku: empty_str.as_ptr(),
                    kid: empty_str.as_ptr(),
                },
                public_key: PublicKeyFfi {
                    x: key_x.as_ptr(),
                    y: key_y.as_ptr(),
                },
            },
        };

        Box::new(PublicKeyOptionHolder {
            key_x,
            key_y,
            empty_str,
            public_key_option,
        })
    }

    ///
    /// Generates the verifier public key option.
    ///
    fn generate_verifier_public_key_option(&self) -> Box<PublicKeyOptionHolder> {
        self.generate_public_key_option(true)
    }

    ///
    /// Generates the issuer public key option.
    ///
    fn generate_issuer_public_key_option(&self) -> Box<PublicKeyOptionHolder> {
        self.generate_public_key_option(false)
    }

    //
    /// Simulates the Proof Verifier's verify_zkpass_proof REST API.
    ///
    pub async fn verify_zkpass_proof(&self, zkvm: &str, zkpass_proof_token: &str) -> String {
        println!("\n#### starting zkpass proof verification...");
        let start = Instant::now();

        let url = std::env
            ::var("ZKPASS_URL")
            .unwrap_or("https://staging-zkpass.ssi.id".to_string());

        let some_ttl: u64 = 3600;
        let dvr_id = unsafe { get_dvr_id_from_proof(zkpass_proof_token) };
        let expected_dvr = DVR_TABLE.lock().unwrap().get(&dvr_id).unwrap().clone();
        let expected_dvr_cstring = CString::new(expected_dvr).unwrap();

        let user_data_requests_holder = self.user_data_requests();
        let user_data_requests = user_data_requests_holder.user_data_requests;
        let user_data_requests_slice = user_data_requests.as_slice();

        //
        // Step 1: Create the expected metadata object.
        //
        let expected_metadata = ExpectedDvrMetadataFfi {
            ttl: some_ttl,
            dvr: expected_dvr_cstring.as_ptr(),
            user_data_verifying_keys: user_data_requests_slice.as_ptr(),
            user_data_verifying_keys_len: user_data_requests_slice.len() as u64,
        };

        //
        // Step 2: Call zkpass_client.verify_zkpass_proof to verify the proof.
        //
        let result = unsafe {
            verify_zkpass_proof_ffi(&url, zkvm, zkpass_proof_token, expected_metadata)
        };

        let duration = start.elapsed();
        println!("#### verification completed [time={:?}]", duration);

        result
    }
}
https://github.com/gl-zkPass/zkpass-sdk/blob/main/rust/zkpass-demo/src/data_holder.rs
/*
 * data_holder.rs
 * Simulating the Data Holder process for the zkPass Demo
 *
 * ---
 * References:
 *   https://docs.ssi.id/zkpass/zkpass-developers-guide/privacy-apps/dvr/dvr-client-roles/data-holder
 * ---
 * Copyright (c) 2024 PT Darta Media Indonesia. All rights reserved.
 */
use crate::{
    data_issuer::DataIssuer,
    proof_verifier::ProofVerifier,
    lib_loader::generate_zkpass_proof,
};
use client_utils::interface::PrivacyAppCredentialsFfi;
use std::{ collections::HashMap, time::Instant, ffi::CString };
use tracing::info;
use zkpass_query_types::OutputReader;

pub struct DataHolder;

impl DataHolder {
    ///
    /// Starts the Data Holder process.
    ///
    pub async fn start(&self, zkvm: &str, data_files: HashMap<String, String>, dvr_file: &str) {
        //
        //  Get the user data from the data issuer
        //
        let data_issuer = DataIssuer;
        let user_data_tokens_map = data_issuer.get_user_data_tokens(data_files);
        let user_data_tags_list: Vec<&String> = user_data_tokens_map.keys().collect();
        let user_data_tokens = serde_json::to_string(&user_data_tokens_map).unwrap();

        //
        //  Get the dvr from the verifier
        //
        let mut proof_verifier = ProofVerifier::default();
        let dvr_token = proof_verifier.get_dvr_token(zkvm, dvr_file, user_data_tags_list);

        let zkpass_service_url = std::env
            ::var("ZKPASS_URL")
            .unwrap_or("https://staging-zkpass.ssi.id".to_string());
        info!("service_url={}", zkpass_service_url);
        println!("\n#### starting zkpass proof generation...");
        let start = Instant::now();

        //
        //  Data Holder's integration points with the zkpass-client SDK library
        //

        //
        // Step 1: Call the dvr client's generate_zk_pass_proof
        //         to get the zkpass_proof_token.
        //
        let credentials = self.generate_credential();
        let zkpass_proof_token = unsafe {
            generate_zkpass_proof(credentials, user_data_tokens, dvr_token)
        };

        let duration = start.elapsed();
        println!("#### generation completed [time={:?}]", duration);

        //
        //  Step 2: Send the zkpass_proof_token to the Proof Verifier
        //          to get the proof verified and retrieve the query result.
        //
        let query_result = proof_verifier.verify_zkpass_proof(zkvm, &zkpass_proof_token).await;

        println!("json-result={}", OutputReader::pretty_print(&query_result));
        let output_reader = OutputReader::from_json(&query_result).unwrap();
        println!(">> output list:");
        for entry in output_reader.enumerate() {
            println!("key={}, value={:?}", entry.key, entry.val);
        }
        println!("<< end of list");

        let val = output_reader.find_bool("result").unwrap();
        println!("the query result is {}", val);
    }

    ///
    /// Generates the privacy app credentials.
    ///
    fn generate_credential(&self) -> PrivacyAppCredentialsFfi {
        let base_url = std::env
            ::var("ZKPASS_URL")
            .unwrap_or("https://staging-zkpass.ssi.id".to_string());
        let api_key = std::env::var("API_KEY").expect("API_KEY must be set");
        let secret_api_key = std::env::var("SECRET_API_KEY").expect("SECRET_API_KEY must be set");

        PrivacyAppCredentialsFfi {
            base_url: CString::new(base_url).unwrap().into_raw(),
            api_key: CString::new(api_key).unwrap().into_raw(),
            secret_api_key: CString::new(secret_api_key).unwrap().into_raw(),
            using_queue: true,
        }
    }
}
https://github.com/gl-zkPass/zkpass-sdk/blob/main/rust/zkpass-demo/src/data_issuer.rs
/*
 * data_issuer.rs
 * Simulating the Data Issuer process for the zkPass Demo
 *
 * ---
 * References:
 *   https://docs.ssi.id/zkpass/zkpass-developers-guide/privacy-apps/dvr/dvr-client-roles/data-issuer
 * ---
 * Copyright (c) 2024 PT Darta Media Indonesia. All rights reserved.
 */
use crate::{ sample_keys::ISSUER_PRIVKEY, lib_loader::generate_user_data_token };
use dvr_types::PublicKeyOptionFfi;
use serde_json::Value;
use std::{ collections::HashMap, io::prelude::*, ffi::CString };
use tracing::info;

// This struct ensures that the data reference is valid
#[allow(dead_code)]
pub struct IssuerPublicKeyOptionHolder {
    jku: CString,
    kid: CString,
    empty_str: CString,
    pub public_key_option: PublicKeyOptionFfi,
}

//
//  Simulating the REST call to the Data Issuer
//
pub struct DataIssuer;

//
//  Simulating the Data Issuer
//
impl DataIssuer {
    //
    // This function simulates the Data Issuer's get_user_data_token REST API
    //
    pub fn get_user_data_tokens(
        &self,
        data_files: HashMap<String, String>
    ) -> HashMap<String, String> {
        //
        // Call the dvr_client.dvr_generate_user_data_token.
        // This is to digitally-sign the user data.
        //
        data_files
            .iter()
            .map(|(data_tag, data_file)| {
                let data = self.read_user_data_token(data_file);
                let data_token = self.sign_user_data_token(data);
                (data_tag.clone(), data_token)
            })
            .collect()
    }

    ///
    /// Signs the user data token.
    ///
    fn sign_user_data_token(&self, data: Value) -> String {
        let user_data_token = unsafe {
            generate_user_data_token(ISSUER_PRIVKEY, &data.to_string())
        };

        user_data_token
    }

    ///
    /// Reads the user data token from the given file path.
    ///
    fn read_user_data_token(&self, data_file: &String) -> Value {
        let mut data_content = std::fs::File
            ::open(data_file)
            .expect("Cannot find the user data file");
        let mut data = String::new();
        data_content.read_to_string(&mut data).expect("Should not have I/O errors");
        info!("data={}", data);

        let data: Value = serde_json::from_str(&data).unwrap();
        data
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn add_dummy_file() {
        let data = r#"{"name": "Alice", "age": 25}"#;
        std::fs::write("./user_data_1.json", data).expect("Unable to write file");
        std::fs::write("./user_data_2.json", data).expect("Unable to write file");
    }

    fn remove_dummy_file() {
        std::fs::remove_file("./user_data_1.json").expect("Unable to remove file");
        std::fs::remove_file("./user_data_2.json").expect("Unable to remove file");
    }

    // on cargo llvm-cov nextest, this test is failing because of SIGSEGV (due to unsafe behavior), but not on cargo test
    #[ignore]
    #[test]
    fn test_get_user_data_tokens() {
        add_dummy_file();
        std::env::set_var(
            "DVR_MODULE_PATH",
            "/home/builder/zkPass/target/release/libdvr_client.so"
        );

        let data_issuer = DataIssuer;
        let data_files = vec![
            ("tag1".to_string(), "./user_data_1.json".to_string()),
            ("tag2".to_string(), "./user_data_2.json".to_string())
        ]
            .into_iter()
            .collect();

        let user_data_tokens = data_issuer.get_user_data_tokens(data_files);
        assert_eq!(user_data_tokens.len(), 2);
        remove_dummy_file();
    }

    #[test]
    #[should_panic]
    fn test_read_user_data_token_error() {
        let data_issuer = DataIssuer;
        let data_file = "./user_data_3.json".to_string();

        let _ = data_issuer.read_user_data_token(&data_file);
    }
}