# Introduction

Navigating the balance between robust identity verification and user privacy is essential in an increasingly digital world. Traditional identity systems, vulnerable to DDoS and single-point failures, fall short in the modern threat landscape.

In this paper, we present zPass, a protocol on the Aleo blockchain that uses zero-knowledge cryptography to empower users with:

* Decentralized identity verification, reducing risks like insider threats or data breaches from unpatched vulnerabilities.
* Anonymous credentials from existing identity documents, streamlining real-world adoption without requiring protocol changes.
* Selective attribute disclosure for user privacy, allowing users to prove identity assertions over multiple credentials.

zPass sets a new standard for fast, secure, and privacy-preserving digital identity.


# Quickstart

### Getting Started with zPass

Install zPass-SDK using

```bash
npm install zpass-sdk
```

As zPass-SDK is using wasm for its core functionality, remember to install wasm supporting packages in your project such as `vite-plugin-wasm` to make sure wasm can be run properly.

It is recommended to setup worker thread in your project to run the `zpass-sdk` properly.

A helper function called `createAleoWorker` is provided in `zpass-sdk` to initialize the worker thread. `worker.js` is the file that will be used to run the worker thread.

```javascript
import { createAleoWorker } from "zpass-sdk";

const AleoWorker = () => {
    return createAleoWorker({
        url: "worker.js",
        baseUrl: import.meta.url,
    });
};

export { AleoWorker };
```

Import `ZPassSDK` from `zpass-sdk` in your `worker.js` file to start using the SDK. An optional `initThreadPool` function is provided to enable multi-threading and improve performance.

```javascript
import { ZPassSDK, initThreadPool } from "zpass-sdk";

await initThreadPool();
```

### ZPass SDK Methods References

Please refer to [Methods References](/zpass-sdk/overview) for the methods references of `zpass-sdk`.

### Example Usage

For example on how to use `zpass-sdk`, please refer to [Step-by-step Guide](/example-usage/step-by-step-guide).


# Background

In today's digital world, users frequently need to verify personal attributes like age, nationality, or membership status. However, this verification process often comes with privacy risks and potential exposure of sensitive personal data. There is a critical need for solutions that enable secure attribute verification while preserving user privacy.

zPass addresses this need by leveraging Aleo's zero-knowledge developer platform and blockchain technology, along with its domain-specific language Leo. This innovative approach enables the creation of privacy-preserving identity verification programs that put users in control of their data while simplifying compliance for platforms and developers.

### The Privacy Challenge

The digital verification of identity attributes presents two fundamental challenges:

* Minimizing unnecessary personal data exposure
* Maintaining compliance with evolving data protection regulations

### Regulatory Environment

Modern data protection frameworks like GDPR and CCPA have established strict requirements for privacy and security. Organizations must now carefully balance effective identity verification with regulatory compliance or face severe penalties and reputational damage.

### Current Solution Limitations

Traditional centralized identity systems struggle with an inherent conflict between security and privacy:

* They often collect excessive data beyond verification requirements
* Despite regulatory compliance, they remain vulnerable to data breaches
* They face ongoing social engineering attack risks

Meanwhile, existing decentralized approaches encounter their own challenges:

* Limited privacy due to transparent blockchain transactions
* Efficiency constraints in processing verifications
* Difficulty maintaining both security and usability

### The zPass Solution

Built on Aleo's blockchain infrastructure, zPass represents a new paradigm in identity verification:

* Leverages zero-knowledge cryptography for privacy-preserving verification
* Adapts flexibly to evolving regulatory requirements
* Provides robust verification while minimizing data exposure
* Ensures compliance with current and future privacy regulations

This innovative approach transforms credential management by combining the security benefits of blockchain technology with the privacy guarantees of zero-knowledge proofs, creating a solution that truly serves both users and verifiers in the modern digital landscape.


# Benefits & Use Cases

Explore the key benefits and real-world applications of zPass

## Benefits

### Security

Decentralization through Aleo's blockchain eliminates single points of failure and minimizes the risk of mass data breaches.

### Privacy

Zero-knowledge proofs (ZKP) ensure that users can validate their credentials without revealing the actual data to verifiers.

### Compatibility

zPass is designed for seamless integration with existing systems, accommodating complex identity requirements without needing adjustments from original issuing authorities.

By focusing on decentralized control, customizable verification, and interoperability, zPass is pioneering a more secure and private user identity experience.

## Use Cases

### Age checks for regulated markets

In fields like online gaming and alcohol sales, zPass offers age verification without the baggage of unnecessary data exposure, making it a win-win for both consumers and vendors.

### Nationality/citizenship confirmation

For global businesses, zPass streamlines nationality verification, ensuring compliance with international laws and enhancing operational efficiency.

### Financial compliance

#### Traditional finance

In KYC and AML domains, zPass sets a new benchmark by marrying trust with data privacy, surpassing standard compliance requisites.

#### Decentralized finance

As DeFi grows, zPass serves as a robust identity layer, ensuring transactions are both speedy and secure, meeting emerging regulatory requirements.

### Reinforcing healthcare privacy

In the US, zPass could reinforce HIPAA compliance by offering "need-to-know" access to medical records, limiting data exposure to authorized individuals only.

### Academic integrity and fast-track approvals

From verifying educational transcripts to authenticating diplomas, zPass brings enhanced integrity and trust to the educational ecosystem and job application domain.

### Simplifying loan and credit approvals

In financial planning, zPass can expedite loan approvals and credit score checks, making these processes as quick as they are secure.

### Comprehensive proof of funds

Whether you're an investor or a homebuyer, zPass could revolutionize proof-of-funds processes, providing rapid, reliable verification while safeguarding sensitive financial data.


# Technical Foundations

## Core mechanics

The backbone of zPass relies on zero-knowledge proofs and, more specifically, zk-SNARKS. The shift to general-purpose zero-knowledge proofs ensures greater privacy and programmability than traditional identity verification systems. Aleo's infrastructure is secure and scalable, providing a strong foundation for zPass.

## Aleo and zero-knowledge proofs

zPass is powered by Aleo, a developer platform extending the capabilities of traditional blockchains using the concept of ZEXE.

### Aleo's role in privacy

Aleo's infrastructure ensures three critical forms of privacy in zPass: private inputs, private outputs, and user privacy.

### Aleo's record model

* Enables storage and encryption of user data while keeping it private in the user's hands
* Extends from Zcash's UTXO model, allowing for complex privacy-preserving applications
* Supports private inputs and outputs

### Decentralized private computation

* Control shifts from centralized databases to end users
* Combines zero-knowledge proofs with off-chain execution for verifications that do not compromise data privacy
* User identity stays private


# System Participants

## Issuer

The Issuer is the trusted entity that issues credentials to substantiate identity claims. The information on a credential is important, but it only truly counts when it's backed up by a trusted authority.

#### `Issuer → Credential → Claim`

` Local government`` `` `**`→`**` ``Driver’s license`` `**`→`**` `` ``Age `

` School`` `` `**`→`**` ``Diploma`` `**`→`**` `` ``Academic Degree `

` Financial bureau`` `` `**`→`**` ``Credit report`` `**`→`**` `` ``Credit score `

` Country`` `` `**`→`**` ``Passport`` `**`→`**` `` ``Nationality `

## Holder

The Holder is the subject of the claims, represented by attributes that exist within credentials. The ability to independently validate these credentials directly correlates with greater autonomy in controlling access to this information.

#### **`Attribute → Credential → Holder`**

` Age`` `` `**`→`**` ``Driver's License`` `**`→`**` `` ``You `

` Academic Degree`` `` `**`→`**` ``Diploma`` `**`→`**` `` ``You `

` Credit score`` `` `**`→`**` ``Credit Report`` `**`→`**` `` ``You `

` Nationality`` `` `**`→`**` ``Passport`` `**`→`**` `` ``You `

## Verifier

The Verifier offers a service and mandates that the user meets specific attribute requirements through credential verification. The focus is on authenticating user identity or claims to decide on service access.

#### **`Required Attribute → Verification Method → Verifier Service`**

` Age`` `` `**`→`**` ``Driver's License Check`` `**`→`**` `` ``Verifier Service `

` Academic Degree`` `` `**`→`**` ``Diploma Verification`` `**`→`**` `` ``Verifier Service `

` Credit score`` `` `**`→`**` ``Credit Report Review`` `**`→`**` `` ``Verifier Service `

` Nationality`` `` `**`→`**` ``Passport Scan`` `**`→`**` `` ``Verifier Service `


# Powered by Aleo

zPass combines the capabilities of zero-knowledge proofs with the nuances of real-world identity, enabling secure interactions in the digital world. Using Aleo as its base, zPass makes digital identities more secure and private, easy to audit, and flexible to use— for both on-chain and off-chain workflows.

## zPass infrastructure

Built on Aleo’s blockchain, zPass inherits the cryptographic capabilities of the ZEXE (Zero-Knowledge EXEcution Environment) model. What sets ZEXE (and therefore Aleo) apart is its innovative use of zero-knowledge proofs, combined with the ability to move execution off-chain.

**Privacy through zero-knowledge proofs:** Zero-knowledge proofs allow users to confirm that a transaction is valid without exposing any of the details behind it. This is crucial for maintaining user privacy in zPass.

**Off-chain execution:** Aleo allows users to execute complex programs offline and then submit a proof of this work to the blockchain. This reduces the load on the network, which in turn speeds up transactions on the network.

**Fast verification:** Aleo’s design allows these proofs to be quickly verified by third parties, making the process both fast and secure.


# Issuer

## Role and responsibilities

**Credential generation**: Creates a digital credential with required attributes like issuer address, subject address, date of birth (DOB), and expiration date.

**Hashing**: Applies cryptographic hash functions to the credential for data integrity.

**Signing**: Uses private key to sign the hashed credential, ensuring its authenticity and source of issuance.

**Issuer–Aleo integration**

* Sign credentials and provide them to the user.
* Sign credentials and provide them as inputs to an Aleo program;
* Create an encrypted tamper-proof record of the credential on-chain.


# Holder

## Roles and responsibilities

**Identity proofing:** Utilizes the signed credential to assert identity or specific claims.

**Record of credential**

The Holder receives an issued credential, for on-chain flow, the credential is provided on the Aleo network as an encrypted record.

**ZKP generation**

* Authorize a credential to use for verification.
* Privately input the credential into an Aleo program.
* Execute program using wasm on local device.
* Generate program output and an execution proof.


# Verifier

## Role and responsibilities

**Claim verification**: Requests and verifies ZKP to confirm the Holder’s identity or specific claims.

**Request for proof**

Initiates a query to the Holder, requesting a ZKP for a specific identity claim.

**Verification workflow**

* Receive the ZKP from the Holder.
* Verify ZKP using corresponding Aleo network protocols.


# Off-chain flow

The off-chain flow offers a path to ensure privacy and trust without depending on the blockchain. These operations can either be initiated and completed off-chain or have their beginnings outside the Aleo ecosystem.

<figure><img src="/files/vcdz0iRdgM330klWTvt9" alt=""><figcaption></figcaption></figure>

Let's break it down into two main sections:

#### Credential Generation (Off-chain)

While zPass provides the tools to generate and manage credentials on the Aleo blockchain, a credential might have an off-chain origin, like a government-issued passport or a university degree. Although produced outside of Aleo's specific programs, these documents can still play a role in zPass.

For instance, consider a passport. Issued by national authorities, passports aren't native to Aleo or any other blockchain system, yet their native signatures allow them to integrate into zPass. Here's how it works:

1. **User Requests a Credential:** An entity (or user) approaches a recognized issuer, like a government agency, for a credential.
2. **Credential Generation by the Issuer:** The issuer, after due verification, creates a digital credential (like a passport) with a native signature for the user.

#### Holder Presentation and Aleo Verification (Off-chain)

1. **Credential Integration:** The Holder who possesses the credential can introduce this credential into the zPass system. Attributes within the passport, like date of birth or nationality, can be converted into a digital format suitable for Aleo's programs.
2. **Local Execution with WebAssembly (Wasm):** To ensure privacy, zPass leverages Wasm, allowing users to run the Aleo program locally. This ensures the user never reveals private inputs or trusts a third party implicitly.
3. **Program Execution and Output:** The program processes the credential (for example by hashing attributes) and produces an output. This output, coupled with an execution proof, does not reveal the credential's data yet acts as verifiable proof that the program ran successfully with the provided credentials.


# On-chain flow

The on-chain flow in the Aleo ecosystem focuses on interactions directly within the blockchain. These interactions provide permissionless privacy and trust. This contrasts the off-chain flow, where operations might be initiated and completed outside the zPass system.

As mentioned in the previous section, credentials may originate from off-chain entities such as government agencies or educational institutions. Although Aleo programs do not generate these credentials, they can be integrated into the on-chain workflow.

<figure><img src="/files/E1tMQg2R9hqNFCG1rRuK" alt=""><figcaption></figcaption></figure>

### On-chain zPass Process

1. **Credential Issuance (On-chain):** Credentials are fed as inputs into Aleo programs, also known as issuance programs. These programs act as trusted authorities for generating the digital equivalents of the real-world credentials, known as zPass. The issuance process includes cryptographic validation of the credential against its digital signature and the Issuer's public key. Successful validation results in issuing a zPass committed to the Aleo blockchain. The recipient of the zPass is termed the "Holder."
2. **Holder Presentation and Verification (On-chain):** Once a zPass is issued and stored on-chain, the Holder can use it for various transactions within the Aleo ecosystem. Aleo programs verify specific claims against the presented zPass, ensuring privacy, data integrity, and establishing trust.


# Local Execution with WASM

## Local Execution with WASM

WebAssembly (WASM) is integral to zPass, designed to maximize user security and data control. Using WASM for client-side data processing, zPass eliminates unnecessary data transfers, reducing exposure risks.

#### Localized data processing

Utilizing WASM, zPass can execute pre-compiled programs directly on the user's device, thus retaining sensitive information within a local environment. This localized approach mitigates the risk of data exposure through network interceptions or server vulnerabilities, ensuring that user data never leaves the client side unless explicitly intended.

#### Trustless ecosystem

The architecture creates a trustless computing ecosystem. It minimizes dependency on third-party servers or intermediaries for data processing, thereby conferring users greater control and assurance over their data. This is especially important for maintaining data integrity and confidentiality.

#### Security advantages

WASM is engineered to enforce the same-origin and permissions security policies of the browser, which makes it an apt choice for secure, controlled execution of code. zPass leverages these inherent security features to establish a secure execution environment for user-specific applications.


# Background

In the Aleo ecosystem, programs are inherently static and predefined, which introduces challenges in supporting dynamic program imports. This limitation makes deploying a universal zPass program capable of accommodating all possible credentials and use cases difficult. As a result, developers interested in using zPass have two primary options: either import an existing zPass program that aligns with their needs or deploy a customized version tailored to their specific use case. Creating a zPass program from scratch requires developers to handle the issuance process themselves and carefully constrain values in supported credentials during zPass issuance.

Another approach to overcome these limitations is to design a universal zPass program that leverages a Merkle tree. In this design, credential data is hashed into leaves, and the Merkle root is passed as a parameter to the program, thus providing flexibility for various credential types without altering the program’s core logic.

Over time, as more zPass programs are developed and the range of supported credentials grows, the ecosystem will become increasingly comprehensive. This progression is expected to reduce the need for future applications to deploy new zPass programs from scratch, as a library of reusable zPass programs will be available.

This section provides an overview of the structure of a zPass program and explains how it can be integrated into applications to address diverse use cases.

**Note**: All of this is still under active development. Features may change substantially or even break in future updates.

## zPass Program Examples

Explore various zPass program implementations:

* [Verify offchain program](/zpass-programs/verify-offchain-program): Demonstrates verifying user credentials offchain using digital signatures to ensure authenticity and privacy.
* [zPass issuance program](/zpass-programs/zpass-issuance-program): Explains how to issue private zPass records containing user credentials with support for flexible value types.
* [zPass hiding program](/zpass-programs/zpass-hiding-program): Showcases the use of randomized commitments to protect user credentials while maintaining privacy.
* [zPass invalidate program](/zpass-programs/zpass-invalidate-program): Introduces logic to invalidate compromised zPass records and support reissuance for enhanced security.
* [zPass invalidate hiding program](/zpass-programs/zpass-invalidate-hiding-program): Combines invalidation and hiding functionalities for robust security and privacy in zPass management.
* [zPass merkle tree size 8 program](/zpass-programs/zpass-merkle-tree-size-8-program): Leverages a Merkle tree-based approach to enable flexible, privacy-preserving credential issuance and selective disclosure with hashed data.

Click on the links to explore each program and learn about their specific functionalities and use cases.


# Verify offchain program

## Example program

```leo
// The 'verify_offchain' program.
program verify_offchain.aleo {
    struct Credentials {
        issuer: address,
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32
    }

    // msg and r are used to construct a public commitment for ownership verification
    // Any message works as long the prover is able to open the commitment
    transition verify(
        msg: field,
        r: scalar,
        sig: signature,
        public issuer: address,
        dob: u32,
        nationality: field,
        expiry: u32
    ) -> public field {
        let creds: Credentials = Credentials {
            issuer: issuer,
            subject: self.signer,
            dob: dob,
            nationality: nationality,
            expiry: expiry
        };
        let res: bool = signature::verify(sig, creds.issuer, Poseidon2::hash_to_field(creds));
        assert_eq(res, true);

        // Return the commitment publicly
        return BHP256::commit_to_field(msg, r);
    }
}
```

The program above demonstrates an example implementation of an offchain verification mechanism using zPass. The `Credentials` can be adjusted to contain any value type supported on Aleo, providing flexibility for various use cases.

In the `verify` transition function, the program takes a `msg`, `random`, `signature` and all values within the `Credentials`. The `signature` is generated by the trusted issuer responsible for attesting to the user's credentials. While Zero-Knowledge Proofs (ZKPs) excel at verifying the correctness of computations or private data without revealing the underlying data, they lack the ability to authenticate the data itself. To overcome this limitation, digital signatures from trusted parties are used to ensure the authenticity of the data. These signatures provide a cryptographic guarantee that the data originates from a legitimate and trusted source, thereby complementing the privacy-preserving and verification strengths of ZKPs.

Within the `verify` transition function, the program reconstructs the hash of the credentials using `self.caller` as the subject, ensuring that the caller is indeed the user. It then asserts that the user’s credentials have been signed by the trusted issuer. To enable transparent verification, the issuer's identity is made publicly visible, allowing the verifier to confirm that the signature originates from a trusted party.

Because the ZKP does not reveal any information including the signer, the verifier has no way to know that valid proof is indeed originated from the claimed subject. To overcome this, a message (`msg`) and a random value (`r`) are used to create a public commitment, which is included with the transaction. The user must later open this commitment to prove that they are the one who generated the ZKP. Any message can be used, as long as the user is able to open the commitment.

If the program executes successfully, the user can generate a ZKP, which can be passed to the verifier. This approach allows the verifier to confirm the validity of the proof without requiring access to the user’s private credentials, maintaining privacy while ensuring security and authenticity.


# Verify onchain program

## Example program

```leo
// The 'verify_onchain' program.
program verify_onchain.aleo {
    // Example admin address that has authority to add or remove issuer
    const ADMIN: address = aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px; 

    struct Credentials {
        issuer: address,
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32
    }

    // Stores approved issuers
    mapping is_issuer: address => bool;

    async transition add_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return add_issuer_finalize(issuer);
    }

    async function add_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, true);
    }

    async transition remove_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return remove_issuer_finalize(issuer);
    }

    async function remove_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, false);
    }

    // msg and r are used to construct a public commitment for ownership verification
    // Any message works as long the prover is able to open the commitment
    async transition verify(
        msg: field,
        r: scalar,
        sig: signature,
        public issuer: address,
        dob: u32,
        nationality: field,
        expiry: u32
    ) -> (public field, Future) {
        let creds: Credentials = Credentials {
            issuer: issuer,
            subject: self.signer,
            dob: dob,
            nationality: nationality,
            expiry: expiry
        };
        let res: bool = signature::verify(sig, creds.issuer, Poseidon2::hash_to_field(creds));
        assert_eq(res, true);

        // Return the commitment publicly
        return (BHP256::commit_to_field(msg, r), verify_finalize(issuer));
    }

    async function verify_finalize(
        public issuer: address
    ) {
        // Ensure the issuer is approved
        assert_eq(is_issuer.get(issuer), true);
    }
}
```

Similar to verifying an off-chain program, but with on-chain storage, the approved issuer can be checked directly on the network without the need to manually read and compare the issuer's address.


# zPass issuance program

```leo
// The 'zpass_issuance' program.
program zpass_issuance.aleo {
    // Example admin address that has authority to add or remove issuer
    const ADMIN: address = aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px; 

    // The ZPass record
    record ZPass {
        owner: address,
        issuer: address,
        dob: u32,
        nationality: field,
        expiry: u32,
        salt: scalar
    }

    // The private credentials struct
    struct PrivateCredentials {
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32
    }

    // The public credentials struct
    // This is the public information that is shared publicly onchain
    struct PublicCredentials {
        issuer: address,
        salt: scalar
    }

    // The full credentials struct to be hashed and verified against the signature
    struct FullCredentials {
        issuer: address,
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32,
        salt: scalar
    }

    // Stores approved issuers
    mapping is_issuer: address => bool;

    // The mapping of issued commitments
    mapping issued: group => bool;

    // The count of issued ZPasses
    // Using key of 0field as global key
    mapping issuance_count: field => u128;

    async transition add_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return add_issuer_finalize(issuer);
    }

    async function add_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, true);
    }

    async transition remove_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return remove_issuer_finalize(issuer);
    }

    async function remove_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, false);
    }

    async transition issue(
        private sig: signature,
        private pri: PrivateCredentials,
        public pub: PublicCredentials,
    ) -> (ZPass, Future) {
        // Construct the full credentials struct to be hashed and verified against the signature
        let credentials: FullCredentials = FullCredentials {
            issuer: pub.issuer,
            subject: self.signer, // The signer must be the subject of the ZPass
            dob: pri.dob,
            nationality: pri.nationality,
            expiry: pri.expiry,
            salt: pub.salt,
        };

        // Verify signature
        assert_eq(signature::verify(sig, pub.issuer, Poseidon2::hash_to_field(credentials)), true);

        // Compute commitment to prevent double issuance
        let commit: group = BHP256::commit_to_group(self.signer, pub.salt);

        // Return the ZPass record and pass the commitment to store in the mapping
        return (ZPass {
            owner: self.signer,
            issuer: pub.issuer,
            dob: pri.dob,
            nationality: pri.nationality,
            expiry: pri.expiry,
            salt: pub.salt
        }, issue_finalize(pub.issuer, commit));
    }

    async function issue_finalize(
        public issuer: address,
        public commit: group
    ) {
        // Ensure the issuer is approved
        assert_eq(is_issuer.get(issuer), true);

        // Ensure the commitment is not already issued
        assert_eq(issued.get_or_use(commit, false), false);

        // Store the commitment in the mapping
        issued.set(commit, true);
        // Increment the issuance count
        issuance_count.set(0field, issuance_count.get_or_use(0field, 0u128) + 1u128);
    }
}
```

The program above demonstrates an example implementation of a zPass issuance program. This program issues a private `zPass` record to a user, which can be utilized in various scenarios, such as third-party applications that support this specific zPass program. The `zPass` record is highly flexible and can contain any value type supported by Aleo, tailored to the needs of the integrating applications. Before issuing a `zPass`, the admin must set at least one approved issuer.

The `Credentials` object is divided into private and public components, allowing the program to selectively disclose certain information publicly while keeping sensitive data private. This design provides flexibility, enabling verifiers to access publicly disclosed information without compromising the privacy of the user.

Additionally, the program introduces three extra mappings to enhance functionality and security. These mappings are used to track the approved issuer, issuance count and prevent double issuance of the same zPass record.

Similar to the [Verify offchain program](/zpass-programs/verify-offchain-program), the `issue` transition reconstructs the full credentials and verifies them against the issuer's signature to ensure authenticity. Once the verification is successful, the program issues a zPass record to the caller and stores the commitment of the credentials on-chain. To enhance security, **salt** is used to add randomness to the commitment, ensuring uniqueness and making it resistant to preimage attacks. This commitment serves as a safeguard to prevent double issuance, ensuring the integrity of the zPass issuance process.


# zPass hiding program

```leo
// The 'zpass_hiding' program.
program zpass_hiding.aleo {
    // Example admin address that has authority to add or remove issuer
    const ADMIN: address = aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px; 

    // The ZPass record
    record ZPass {
        owner: address,
        issuer: group,
        dob: group,
        nationality: group,
        expiry: group,
        salt: scalar
    }

    // The private credential struct
    struct PrivateCredential {
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32
    }

    // The public credential struct
    // This is the public information that is shared publicly onchain
    struct PublicCredential {
        issuer: address,
        salt: scalar
    }

    // The full credentials struct to be hashed and verified against the signature
    struct FullCredentials {
        issuer: address,
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32,
        salt: scalar
    }

    // Stores approved issuers
    mapping is_issuer: address => bool;

    // The mapping of issued commitments
    mapping issued: group => bool;

    // The count of issued ZPasses
    // Using key of 0field as global key
    mapping issuance_count: field => u128;

    async transition add_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return add_issuer_finalize(issuer);
    }

    async function add_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, true);
    }

    async transition remove_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return remove_issuer_finalize(issuer);
    }

    async function remove_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, false);
    }

    async transition issue(
        private sig: signature,
        private pri: PrivateCredential,
        public pub: PublicCredential,
    ) -> (ZPass, Future) {
        // Construct the full credentials struct to be hashed and verified against the signature
        let credentials: FullCredentials = FullCredentials {
            issuer: pub.issuer,
            subject: self.signer, // The signer must be the subject of the ZPass
            dob: pri.dob,
            nationality: pri.nationality,
            expiry: pri.expiry,
            salt: pub.salt,
        };

        // Verify signature
        assert_eq(signature::verify(sig, pub.issuer, Poseidon2::hash_to_field(credentials)), true);

        // Compute commitment to prevent double issuance
        let commit: group = BHP256::commit_to_group(self.signer, pub.salt);

        // Return the ZPass record and pass the commitment to store in the mapping
        return (ZPass {
            owner: self.signer,
            issuer: BHP256::commit_to_group(pub.issuer, pub.salt),
            dob: BHP256::commit_to_group(pri.dob, pub.salt),
            nationality: BHP256::commit_to_group(pri.nationality, pub.salt),
            expiry: BHP256::commit_to_group(pri.expiry, pub.salt),
            salt: pub.salt
        }, issue_finalize(pub.issuer, commit));
    }

    async function issue_finalize(
        public issuer: address,
        public commit: group
    ) {
        // Ensure the issuer is approved
        assert_eq(is_issuer.get(issuer), true);

        // Ensure the commitment is not already issued
        assert_eq(issued.get_or_use(commit, false), false);

        // Store the commitment in the mapping
        issued.set(commit, true);
        // Increment the issuance count
        issuance_count.set(0field, issuance_count.get_or_use(0field, 0u128) + 1u128);
    }

    // Sample transition to check if the dob is more than certain age
    transition more_than_18(
        dob: u32,
        dob_check: u32,
        zpass: ZPass
    ) -> ZPass {
        // Ensure knowledge of the dob commitment
        assert_eq(zpass.dob, BHP256::commit_to_group(dob, zpass.salt));
        // Ensure the dob is more than certain age
        assert_eq(dob > dob_check, true);
        // Return ZPass to avoid burning after validation
        return zpass;
    }
}
```

Similar to the [zPass issuance program](/zpass-programs/zpass-issuance-program), the values in the zPass are converted into commitments using a salt as randomness. This approach enhances the security of user-confidential information, providing additional protection against rare scenarios such as private key or view key compromise. However, this added layer of security introduces a tradeoff: users are required to remember and re-enter these private values when utilizing their zPass in applications.

The `more_than_18` transition provides an example of how a private value from the zPass can be used. In this transition, the commitment is reconstructed from the user-provided input values to verify the user's knowledge of the original values, ensuring that only the rightful user can access or utilize the zPass data.


# zPass invalidate program

```leo
// The 'zpass_invalidate' program.
program zpass_invalidate.aleo {
    // Example admin address that has authority to add or remove issuer
    const ADMIN: address = aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px; 

    // The ZPass record
    record ZPass {
        owner: address,
        issuer: address,
        dob: u32,
        nationality: field,
        expiry: u32,
        salt: scalar
    }

    // The private credentials struct
    struct PrivateCredentials {
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32
    }

    // The public credentials struct
    // This is the public information that is shared publicly onchain
    struct PublicCredentials {
        issuer: address,
        salt: scalar
    }

    // The full credentials struct to be hashed and verified against the signature
    struct FullCredentials {
        issuer: address,
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32,
        salt: scalar
    }

    // Stores approved issuers
    mapping is_issuer: address => bool;

    // The mapping of issued commitments
    mapping issued: group => bool;

    // The mapping of invalidated commitments
    mapping invalidated: group => bool;

    // The count of issued ZPasses
    // Using key of 0field as global key
    mapping issuance_count: field => u128;

    async transition add_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return add_issuer_finalize(issuer);
    }

    async function add_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, true);
    }

    async transition remove_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return remove_issuer_finalize(issuer);
    }

    async function remove_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, false);
    }

    async transition issue(
        private sig: signature,
        private pri: PrivateCredentials,
        public pub: PublicCredentials,
    ) -> (ZPass, Future) {
        // Construct the full credentials struct to be hashed and verified against the signature
        let credentials: FullCredentials = FullCredentials {
            issuer: pub.issuer,
            subject: self.signer, // The signer must be the subject of the ZPass
            dob: pri.dob,
            nationality: pri.nationality,
            expiry: pri.expiry,
            salt: pub.salt,
        };

        // Verify signature
        assert_eq(signature::verify(sig, pub.issuer, Poseidon2::hash_to_field(credentials)), true);

        // Compute commitment to prevent double issuance
        let commit: group = BHP256::commit_to_group(self.signer, pub.salt);

        // Return the ZPass record and pass the commitment to store in the mapping
        return (ZPass {
            owner: self.signer,
            issuer: pub.issuer,
            dob: pri.dob,
            nationality: pri.nationality,
            expiry: pri.expiry,
            salt: pub.salt
        }, issue_finalize(pub.issuer, commit));
    }

    async function issue_finalize(
        public issuer: address,
        public commit: group
    ) {
        // Ensure the issuer is approved
        assert_eq(is_issuer.get(issuer), true);

        // Ensure the commitment is not already issued
        assert_eq(issued.get_or_use(commit, false), false);

        // Store the commitment in the mapping
        issued.set(commit, true);
        // Increment the issuance count
        issuance_count.set(0field, issuance_count.get_or_use(0field, 0u128) + 1u128);
    }

    // Must know the details of the ZPass to invalidate it
    // subject in FullCredentials is owner of the ZPass to invalidate
    async transition invalidate(
        credentials: FullCredentials
    ) -> Future {
        let commit: group = BHP256::commit_to_group(credentials, credentials.salt);
        return invalidate_finalize(commit);
    }

    // Helper function to check validity of ZPass
    async function invalidate_finalize(
        public commit: group
    ) {
        // Store the commitment in the mapping
        invalidated.set(commit, true);
    }

    async transition is_invalid(
        credentials: FullCredentials
    ) -> Future {
        let commit: group = BHP256::commit_to_group(credentials, credentials.salt);
        return is_invalid_finalize(commit);
    }

    async function is_invalid_finalize(
        public commit: group
    ) {
        assert_eq(invalidated.get_or_use(commit, false), false);
    }
}
```

This program enhances the [zPass issuance program](/zpass-programs/zpass-issuance-program) by introducing a new mapping called `invalidated`. This mapping is used to store the commitments of zPass records that have been invalidated. Invalidation may occur in cases where the rightful owner no longer has exclusive access to their zPass, such as when an account is compromised. In such scenarios, the user can choose to reissue a new zPass associated with a different account.

To ensure the validity of a zPass, an `is_invalid` transition is added. This transition allows importing programs to verify whether a zPass has been invalidated by passing all the private information from the zPass. This process guarantees the integrity of the zPass and ensures that only the rightful owner can utilize it, maintaining its exclusivity and security.


# zPass invalidate hiding program

```leo
// The 'zpass_invalidate_hiding' program.
program zpass_invalidate_hiding.aleo {
    // Example admin address that has authority to add or remove issuer
    const ADMIN: address = aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px; 

    // The ZPass record
    record ZPass {
        owner: address,
        issuer: group,
        dob: group,
        nationality: group,
        expiry: group,
        salt: scalar
    }

    struct InvalidateZPass {
        issuer: group,
        subject: address,
        dob: group,
        nationality: group,
        expiry: group,
        salt: scalar
    }

    // The private credential struct
    struct PrivateCredential {
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32
    }

    // The public credential struct
    // This is the public information that is shared publicly onchain
    struct PublicCredential {
        issuer: address,
        salt: scalar
    }

    // The full credentials struct to be hashed and verified against the signature
    struct FullCredentials {
        issuer: address,
        subject: address,
        dob: u32,
        nationality: field,
        expiry: u32,
        salt: scalar
    }

    // Stores approved issuers
    mapping is_issuer: address => bool;

    // Store the commitment of the user address to prevent double issuance
    mapping issued: group => bool;

    // Store the commitment of the credentials to invalidate the ZPass
    mapping invalidated: group => bool;

    // The count of issued ZPasses
    // Using key of 0field as global key
    mapping issuance_count: field => u128;

    async transition add_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return add_issuer_finalize(issuer);
    }

    async function add_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, true);
    }

    async transition remove_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return remove_issuer_finalize(issuer);
    }

    async function remove_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, false);
    }

    async transition issue(
        private sig: signature,
        private pri: PrivateCredential,
        public pub: PublicCredential,
    ) -> (ZPass, Future) {
        // Construct the full credentials struct to be hashed and verified against the signature
        let credentials: FullCredentials = FullCredentials {
            issuer: pub.issuer,
            subject: self.signer, // The signer must be the subject of the ZPass
            dob: pri.dob,
            nationality: pri.nationality,
            expiry: pri.expiry,
            salt: pub.salt,
        };

        // Verify signature
        assert_eq(signature::verify(sig, pub.issuer, Poseidon2::hash_to_field(credentials)), true);

        // Compute commitment to prevent double issuance
        let commit: group = BHP256::commit_to_group(self.signer, pub.salt);

        // Return the ZPass record and pass the commitment to store in the mapping
        return (ZPass {
            owner: self.signer,
            issuer: BHP256::commit_to_group(pub.issuer, pub.salt),
            dob: BHP256::commit_to_group(pri.dob, pub.salt),
            nationality: BHP256::commit_to_group(pri.nationality, pub.salt),
            expiry: BHP256::commit_to_group(pri.expiry, pub.salt),
            salt: pub.salt
        }, issue_finalize(pub.issuer, commit));
    }

    async function issue_finalize(
        public issuer: address,
        public commit: group
    ) {
        // Ensure the issuer is approved
        assert_eq(is_issuer.get(issuer), true);
        
        // Ensure the commitment is not already issued
        assert_eq(issued.get_or_use(commit, false), false);

        // Store the commitment in the mapping
        issued.set(commit, true);
        // Increment the issuance count
        issuance_count.set(0field, issuance_count.get_or_use(0field, 0u128) + 1u128);
    }

    // Must know the details of the ZPass to invalidate it
    // subject in FullCredentials is owner of the ZPass to invalidate
    async transition invalidate(
        credentials: InvalidateZPass
    ) -> Future {
        let commit: group = BHP256::commit_to_group(credentials, credentials.salt);
        return invalidate_finalize(commit);
    }

    async function invalidate_finalize(
        public commit: group
    ) {
        // Store the commitment in the mapping
        invalidated.set(commit, true);
    }

    // Helper function to check validity of ZPass
    async transition is_invalid(
        credentials: InvalidateZPass
    ) -> Future {
        let commit: group = BHP256::commit_to_group(credentials, credentials.salt);

        return is_invalid_finalize(commit);
    }

    async function is_invalid_finalize(
        public commit: group
    ) {
        assert_eq(invalidated.get_or_use(commit, false), false);
    }

    // Sample transition to check if the dob is more than certain age
    transition more_than_18(
        dob: u32,
        dob_check: u32,
        zpass: ZPass
    ) -> ZPass {
        // Ensure knowledge of the dob commitment
        assert_eq(zpass.dob, BHP256::commit_to_group(dob, zpass.salt));
        // Ensure the dob is more than certain age
        assert_eq(dob > dob_check, true);
        // Return ZPass to avoid burning after validation
        return zpass;
    }
}
```

This example demonstrates the integration of both the zPass invalidation and data-hiding functionalities, showcasing how these features can work together seamlessly within a single program.


# zPass merkle tree size 8 program

```leo
// The 'zpass_merkle_8' program.
program zpass_merkle_8.aleo {
    // Example admin address that has authority to add or remove issuer
    const ADMIN: address = aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px; 

    // The ZPass record
    record ZPass {
        owner: address,
        issuer: address,
        root: field,
    }

    // Stores approved issuers
    mapping is_issuer: address => bool;

    async transition add_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return add_issuer_finalize(issuer);
    }

    async function add_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, true);
    }

    async transition remove_issuer(
        public issuer: address
    ) -> Future {
        assert_eq(self.caller, ADMIN);
        return remove_issuer_finalize(issuer);
    }

    async function remove_issuer_finalize(
        issuer: address
    ) {
        is_issuer.set(issuer, false);
    }

    function get_merkle_tree(leaves_hashes: [field; 8]) -> (field, [field; 2], [field; 4]) {
        let third_level_nodes: [field; 4] = [
            Poseidon2::hash_to_field(leaves_hashes[0u8] + leaves_hashes[1u8]),
            Poseidon2::hash_to_field(leaves_hashes[2u8] + leaves_hashes[3u8]),
            Poseidon2::hash_to_field(leaves_hashes[4u8] + leaves_hashes[5u8]),
            Poseidon2::hash_to_field(leaves_hashes[6u8] + leaves_hashes[7u8]),
        ];

        let second_level_nodes: [field; 2] = [
            Poseidon2::hash_to_field(third_level_nodes[0u8] + third_level_nodes[1u8]),
            Poseidon2::hash_to_field(third_level_nodes[2u8] + third_level_nodes[3u8]),
        ];

        let root_hash: field = Poseidon2::hash_to_field(second_level_nodes[0u8] + second_level_nodes[1u8]);

        return (root_hash, second_level_nodes, third_level_nodes);
    }
    
    // External function to get the merkle tree
    transition get_merkle(leaves_hashed: [field; 8]) -> (field, [field; 2], [field; 4]) {
        return get_merkle_tree(leaves_hashed);
    }

    async transition issue(
        private sig: signature,
        private leaves_hashes: [field; 8],
        public issuer: address,
    ) -> (ZPass, Future) {
        // Verify the first leaf is the issuer
        assert_eq(leaves_hashes[0u8], Poseidon2::hash_to_field(issuer));

        // Get the merkle tree
        let merkle_tree: (field, [field; 2], [field; 4]) = get_merkle_tree(leaves_hashes);

        // Verify signature against root 
        assert_eq(signature::verify(sig, issuer, merkle_tree.0), true);

        // Return the ZPass record and pass the commitment to store in the mapping
        return (ZPass {
            owner: self.signer,
            issuer: issuer,
            root: merkle_tree.0,
        }, issue_finalize(issuer));
    }

    async function issue_finalize(
        public issuer: address,
    ) {
        // Ensure the issuer is approved
        assert_eq(is_issuer.get(issuer), true);
    }

    // msg and r are used to construct a public commitment for ownership verification
    // Any message works as long the prover is able to open the commitment
    transition verify(
        msg: field,
        r: scalar,
        zpass: ZPass, 
        leaf_hash: field, 
        merkle_proof: [field; 3]
    ) -> (
        public field,
        bool,
        ZPass
    ) {
        let element: field = leaf_hash;

        for i: u8 in 0u8..3u8 {
            // Order does not matter because of the commutative property of group addition
            element = Poseidon2::hash_to_field(element + merkle_proof[i]);
        }
        assert_eq(element, zpass.root);

        // Creates the commitment and return publicly
        let commitment: field = BHP256::commit_to_field(msg, r);

        // Return ZPass to avoid burning after validation
        return (commitment, true, zpass);
    }
}
```

## **Overview**

This program illustrates a design where credential fields (such as issuer, subject, date of birth, or any other fields) are first hashed into an array of leaf nodes. These leaves are then used to construct a Merkle tree, whose root is stored on-chain. The steps below outline the key components and their purposes:

1. **`ZPass` Record**
   * Defines the core information of a zPass credential in this example:
     * `owner`: The address of the credential holder (the caller who receives the zPass).
     * `issuer`: The address of the entity issuing the credential.
     * `root`: The Merkle root representing the hashed credential data.
2. **`get_merkle_tree` Function**
   * Given an array of eight hashed leaves (`[field; 8]`), it constructs a small, fixed-depth Merkle tree.
   * It returns the Merkle tree root, the second-level nodes, and the third-level nodes (leaf hashes aggregated two-by-two).
3. **`get_merkle` Transition**
   * Externally callable function that returns the Merkle tree structure (root, second-level nodes, third-level nodes) for the given leaves.
   * Primarily a convenience transition for on-chain callers who need to compute or verify the Merkle tree within the same program.
4. **`issue` Transition**
   * Responsible for issuing a ZPass record.
   * It takes three parameters:
     * `sig`: A private signature proving the issuer’s authority.
     * `leaves_hashes`: An array of eight hashed fields that collectively form the credential data.
     * `issuer`: The address of the credential issuer.
   * Validates that:
     1. The first leaf belongs to the issuer.
     2. The issuer’s signature correctly verifies against the computed Merkle root.
   * Once validated, it generates a new `ZPass` record where `root` corresponds to the Merkle root of the hashed leaves.
5. **`verify` Transition**
   * Enables verification that a single leaf was indeed part of the Merkle tree used to create the `ZPass` record.
   * Takes:
     * `zpass`: The existing ZPass record to verify against.
     * `leaf_hash`: The individual hashed leaf.
     * `merkle_proof`: The array of sibling nodes needed to recompute the path up to the Merkle root.
   * Performs step-by-step hashing with the sibling proofs until it reconstructs and checks it against the `zpass.root`.
   * Creates a public commitment from `msg` and `r` to demonstrate authorship of the proof.

***

## **How It Works**

1. **Hashing & Leaf Construction**:
   * Before calling `issue`, developers must hash each credential field and store the results in an 8-element array (`[field; 8]`).
2. **Merkle Root Generation & Signature**:
   * Inside `issue`, the program calls `get_merkle_tree` to derive the Merkle root.
   * The issuer signs this root off-chain, and the signature (`sig`) is verified on-chain to confirm authenticity.
3. **ZPass Creation**:
   * Upon verification, the program returns a new `ZPass` record containing the `owner`, `issuer`, and the computed `root`.
4. **Verification**:
   * The `verify` transition confirms that a specific leaf (e.g., a hashed credential field) is part of the `ZPass` root.
   * It reconstructs the path with the supplied `merkle_proof` and ensures the resulting hash matches the `ZPass` root.


# Methods References

The ZPass SDK provides a comprehensive set of methods for interacting with ZPass credentials on the Aleo blockchain.

## Core Operations

### Credential Management

* [signCredential](/zpass-sdk/overview/signcredential) - Sign credential data with a private key
* [issueZPass](/zpass-sdk/overview/issuezpass) - Issue a new ZPass credential on-chain
* [getZPassRecord](/zpass-sdk/overview/getzpassrecord) - Retrieve and decrypt a ZPass record from the blockchain

### Proof Operations

* [proveOnChain](/zpass-sdk/overview/proveonchain) - Generate an on-chain proof for a ZPass credential
* [proveOffChain](/zpass-sdk/overview/proveoffchain) - Generate an off-chain proof locally
* [verifyOnChain](/zpass-sdk/overview/verifyonchain) - Verify an on-chain ZPass proof
* [verifyOffChain](/zpass-sdk/overview/verifyoffchain) - Verify an off-chain ZPass proof locally

### Merkle Tree Operations

* [getMerkleRoot](/zpass-sdk/overview/getmerkleroot) - Computes the Merkle root from an array of leaves
* [getMerkleTree](/zpass-sdk/overview/getmerkletree) **-** Constructs and serializes a Merkle tree from a list of leaves.
* [getMerkleProof](/zpass-sdk/overview/getmerkleproof) **-** Generates a Merkle proof for a specified leaf index.
* [getLeavesHashes](/zpass-sdk/overview/getleaveshashes) **-** Hashes an array of raw values to produce leaf nodes.
* [signMerkleRoot](/zpass-sdk/overview/signmerkleroot) **-** Signs a Merkle root using the account’s private key.

## Worker Management

* [createAleoWorker](/zpass-sdk/overview/createaleoworker) - Create a Web Worker for Aleo computations
* [initThreadPool](/zpass-sdk/overview/initthreadpool) - Initialize a thread pool for improved performance

## Getting Started

For a quick introduction to using the SDK, check out [Quickstart](/zpass/quickstart).


# constructor

## Description

The `ZPassSDK` provides an interface for interacting with the ZPass, including program management, account handling, and network communication. It leverages WebAssembly and supports integration with Aleo's ecosystem.

### Parameters

* **`privateKey` (string)**: The private key for the Aleo account. Must start with `APrivateKey1`.
* **`host` (string, optional)**: The API host for the network client. Defaults to `https://api.explorer.provable.com/v1` if not provided.

### Example

```javascript
const sdk = new ZPassSDK({
    privateKey: 'APrivateKey1...',
    host: 'http://localhost:3030'
});
```


# setNewHost

## Description

The `setNewHost` method allows you to update the host URL for the `ProgramManager`. This is useful if the API endpoint for your Aleo network changes or if you need to switch between different environments (e.g., staging, production).

### Parameters

* **`host` (string)**: The new host URL to be set for the `ProgramManager`. It must be a valid URL.

### Example&#x20;

```javascript
zpassSdk.setNewHost('http://localhost:3030');
```


# issueZPass

## Description

The `issueZPass` method allows you to issue a new ZPass credential on-chain. This method handles the on-chain interaction for creating a new ZPass credential.

### Parameters

* **`options` (OnChainOptions)**: An object containing the necessary parameters for on-chain interaction:
  * **`programName` (string)**: The Aleo program name
  * **`functionName` (string)**: Name of the function to execute
  * **`inputs` (string\[])**: Array of input parameters for the function
  * **`fee` (number)**: Transaction fee in microcredits
  * **`privateFee` (boolean)**: Whether to use private fee
  * **`feeRecord` (string, optional)**: Record for private fee payment if private fee is used

### Returns

Returns a Promise that resolves to a string containing the transaction ID of the issued ZPass.

* **`transactionId` (string)**: The transaction ID of the issued ZPass

### Example

```javascript
const transactionId = await zpass.issueZPass({
    programName,
    functionName: functionName,
    inputs: [signature, `{
      issuer: ${issuer},
      subject: ${subject},
      dob: ${dob},
      nationality: ${nationality},
      expiry: ${expiry}
    }`,
      `{ salt: ${salt} }`,
    ],
    fee: 300000,
    privateFee: false,
  });
```


# getZPassRecord

## Description

The `getZPassRecord` method retrieves and decrypts a ZPass record from a transaction on the blockchain.

### Parameters

* **`transactionId` (string)**: The ID of the transaction containing the ZPass record

### Returns

Returns a Promise that resolves to a string containing the decrypted record data.

### Example

```javascript
const record = await zpass.getZPassRecord("at1xyz...");
```

### Errors

Throws `SDKError` if:

* No outputs are found in the transaction
* No record is found in the transaction outputs


# proveOnChain

## Description

The `proveOnChain` method generates an on-chain proof for a ZPass credential.

### Parameters

* **`options` (OnChainOptions)**: An object containing:
  * **`program` (string)**: The Aleo program source code
  * **`functionName` (string)**: Name of the function to execute
  * **`inputs` (string\[])**: Array of input parameters for the function
  * **`fee` (number, optional)**: Transaction fee in microcredits
  * **`password` (string, optional)**: Password for key encryption

### Returns

Returns a Promise that resolves to a string containing the transaction ID of the proof.

### Example

```javascript
const transactionId = await zpass.proveOnChain({
    program: programSource,
    functionName: "prove_credential",
    inputs: ["record1234", "2u32"],
    fee: 1000000
});
```


# proveOffChain

## Description

The `proveOffChain` method generates an off-chain proof for a ZPass credential, executing the program locally without submitting to the blockchain. The program can be both deployed on-chain or a local program that is not deployed on-chain but is provided and agreed upon by all the involved parties (issuer, user, verifier).

### Parameters

* **`options` (ProveOffChainOptions)**: An object containing:
  * **`localProgram` (string)**: The Aleo program source code
  * **`functionName` (string)**: Name of the function to execute
  * **`inputs` (string\[])**: Array of input parameters for the function
  * **`offlineQuery` (OfflineQuery, optional)**: An optional offline query object used to insert the global state root and state paths needed to create a valid inclusion proof offline.

### Returns

Returns a Promise that resolves to an object containing:

* **`outputs` (string\[])**: Array of function outputs
* **`execution` (string)**: The execution trace
* **`verifyingKey` (string)**: The verifying key for the proof

### Example

```javascript
const { outputs, execution, verifyingKey } = await zpass.proveOffChain({
    localProgram: programSource,
    functionName: functionName,
    inputs: [signature, `{
      issuer: ${issuer},
      subject: ${subject},
      dob: ${dob},
      nationality: ${nationality},
      expiry: ${expiry}
    }`,
      `{ salt: ${salt} }`,
    ],
});
```


# verifyOnChain

## Description

The `verifyOnChain` static method verifies an on-chain ZPass proof by checking the transaction on the blockchain.

### Parameters

* **`options` (VerifyOnChainOptions)**: An object containing:
  * **`transactionId` (string)**: The ID of the transaction to verify
  * **`url` (string, optional)**: Custom API endpoint URL (defaults to "<https://api.explorer.provable.com/v1>")

### Returns

Returns a Promise that resolves to an object containing:

* **`hasExecution` (boolean)**: Whether the transaction contains an execution, only true if the transaction has a valid execution finalized on-chain (meaning the transaction proof is valid).
* **`outputs` (Output\[])**: Array of transaction outputs

### Example

```javascript
const result = await ZPass.verifyOnChain({
    transactionId: "at1xyz...",
    url: "http://localhost:3030"
});
```


# verifyOffChain

### Description

The `verifyOffChain` static method verifies an off-chain ZPass proof locally without accessing the blockchain.

### Parameters

* **`options` (VerifyOffChainOptions)**: An object containing:
  * **`execution` (string)**: The execution trace to verify, output of `proveOffChain`
  * **`program` (string)**: The Aleo program source code
  * **`functionName` (string)**: Name of the function that was executed
  * **`inputs` (string\[], optional)**: Array of input parameters used, must be provided if `verifyingKey` is not provided
  * **`verifyingKey` (string, optional)**: The verifying key for the proof, must be provided if `inputs` is not provided
  * **`url` (string, optional)**: Custom API endpoint URL, for keys synthesizing purpose

### Returns

Returns a Promise that resolves to a boolean indicating whether the proof is valid.

### Example

```javascript
const isValid = await ZPass.verifyOffChain({
    execution: executionTrace,
    program: programSource,
    functionName: "verify_credential",
    verifyingKey: verifyingKey,
});
```

### Notes

Either `inputs` or `verifyingKey` must be provided. If both are provided, `verifyingKey` takes precedence.

If `verifyingKey` is not provided, the SDK will synthesize the verifying key from the inputs and the program.

Synthesizing the verifying key is a computationally expensive operation, so it is recommended to provide the verifying key if possible.


# signCredential

## Description

The `signCredential` method allows you to hash credential data and sign it with a private key. This is useful for the issuer to create digital signatures that can verify the authenticity and integrity of data.

### Parameters

* **`options` (SignCredentialOptions)**: An object containing:
  * **`data` (object)**: The data to be signed, can be any properties and values type that are supported by Leo program
  * **`hashType` (HashAlgorithm)**: The hashing algorithm to use, type can be imported from `zpass-sdk`
  * **`privateKey` (string, optional)**: Optional private key to use for signing. If not provided, uses the SDK instance's private key

### Returns

Returns a Promise that resolves to an object containing:

* **`signature` (string)**: The generated signature
* **`hash` (string)**: The hash of the data

### Example

```javascript
const { signature, hash } = await zpass.signCredential({
    data: {
      issuer: issuer,
      subject: subject,
      dob: dob,
      nationality: nationality,
      expiry: expiry,
      salt: salt,
    },
    hashType: HashAlgorithm.POSEIDON2,
  });
```


# initThreadPool

## Description

The `initThreadPool` method initializes a thread pool of Workers to enable multi-threading, which significantly improves performance.

### Returns

Returns a Promise that resolves when the thread pool has been successfully initialized.

### Example

```javascript
await initThreadPool();
```


# createAleoWorker

## Description

The `createAleoWorker` method creates a new Web Worker instance for handling Aleo computations. This is useful for offloading heavy cryptographic operations to a separate thread to avoid blocking the main thread.

### Parameters

* **`options` (CreateAleoWorkerOptions)**: An object containing:
  * **`url` (string)**: URL of the worker script file
  * **`baseUrl` (string, optional)**: Base URL to resolve the worker script URL against

### Returns

Returns a wrapped Worker instance configured for Aleo operations using Comlink.

### Example

```javascript
import { createAleoWorker } from "zpass-sdk";

const AleoWorker = () => {
    return createAleoWorker({url: "worker.js", baseUrl: import.meta.url});
};

export { AleoWorker };
```


# getMerkleRoot

**Description**\
The `getMerkleRoot` method computes the Merkle root from a list of input values.

**Parameters**

* `inputs` (`string[]`): An array of strings representing the hashed leaf nodes of the Merkle tree.

**Returns**\
Returns a `Promise` that resolves to a `string` containing the Merkle root.

**Example**

```typescript
const merkleRoot = await sdk.getMerkleRoot(["leafHash1", "leafHash2", "leafHash3"]);
console.log("Merkle Root:", merkleRoot);
```


# getMerkleTree

**Description**\
The `getMerkleTree` method constructs the complete Merkle tree from a list of input values.

**Parameters**

* `inputs` (`string[]`): An array of strings representing the hashed leaf nodes of the Merkle tree.

**Returns**\
Returns a `Promise` that resolves to a `string` containing the serialized Merkle tree.

**Example**

```typescript
const merkleTree = await sdk.getMerkleTree(["leafHash1", "leafHash2", "leafHash3"]);
console.log("Merkle Tree:", merkleTree);
```


# getMerkleProof

**Description**\
The `getMerkleProof` method generates a Merkle proof for a specific leaf in the Merkle tree.

**Parameters**

* `inputs` (`string[]`): An array of strings representing the hashed leaf nodes of the Merkle tree.
* `index` (`number`): The index of the leaf for which to generate the proof.

**Returns**\
Returns a `Promise` that resolves to a `string[]` containing the Merkle proof (sibling hashes).

**Example**

```typescript
const proof = await sdk.getMerkleProof(["leafHash1", "leafHash2", "leafHash3"], 1);
console.log("Merkle Proof:", proof);
```


# getLeavesHashes

**Description**\
The `getLeavesHashes` method hashes the input values to generate leaf hashes for the Merkle tree.

**Parameters**

* `inputs` (`string[]`): An array of strings representing the raw data for the leaves.

**Returns**\
Returns a `Promise` that resolves to a `string[]` containing the hashed leaf nodes. Always append to size of 8 with `0field` if data length is < 8.

**Example**

```typescript
const hashes = await sdk.getLeavesHashes(["data1", "data2", "data3"]);
console.log("Leaf Hashes:", hashes);
```


# signMerkleRoot

**Description**\
The `signMerkleRoot` method signs the Merkle root using the account's private key.

**Parameters**

* `root` (`string`): The Merkle root to be signed.

**Returns**\
Returns a `Promise` that resolves to a `string` containing the signature of the Merkle root.

**Example**

```typescript
const signature = await sdk.signMerkleRoot(root);
console.log("Signed Merkle Root:", signature);
```


# Step-by-step Guide

## Setup

1. Install `zPass-SDK` using `npm install zpass-sdk.`
2. As `zPass-SDK` is using wasm for core functionality, install wasm supporting packages such as `vite-plugin-wasm` to make sure wasm can be run properly.
3. Create a worker directory in your project.
4. Create an `AleoWorker.js` file, import `createAleoWorker()` helper function to help initialize and manage workers.
5. The `createAleoWorker()` takes an argument of an object with 2 values which are `URL` and optional `baseURL`, the url here is referring to the location of `worker.js` file that we are going to define our zPass functions in later. For example, if the `worker.js` is located at the same location as the `AleoWorker.js` file, the arguments of `createAleoWorker()` will be `{“worker.js”, import.meta.url}`. The `import.meta.url` will return the absolute URL of the current module regardless of how the application is deployed or served.

```javascript
import { createAleoWorker } from "zpass-sdk";
const AleoWorker = () => {
    return createAleoWorker({
        url: "worker.js",
        baseUrl: import.meta.url,
    });
};
export { AleoWorker };
```

6. Move on to create a new `worker.js` file to build zPass functions in worker using `zPass-SDK`.
7. In `worker.js` file, import and call `initThreadPool()` to initialize a thread pool of Workers. This enables multi-threading, which significantly improves performance.
8. Then proceed to create own zPass functions using `zPass-SDK`, these functions will be later exposed to the main threat using `expose()` from `comlink`. The `expose()` method takes an argument of an object with all the functions defined in `workers.js`.

## Using zPass

1. (Optional) Import `initThreadPool` to initialize a thread pool of workers to enable multi-threading and improve performance.
2. Import `ZPassSDK` into `worker.js`, initialize ZPassSDK with user `privateKey` and optional `host` url to connect to the rpc node of Aleo network.

```javascript
const sdk = new ZPassSDK({
    privateKey: privateKey,
    host: host
});
```

3. Import `expose` from `comlink` to expose functions that are created in `worker.js` later.
4. To start using zPass on-chain, a zPass program must be deployed onto the network or use any zPass program that has been deployed. Check out this [guide](/zpass/background) on how to write a zPass program to prove certain credentials requirements.
5. Once a zPass program is deployed on-chain, the first thing to do is to get the issuer to sign the credentials defined in the zPass program so that the users can issue themselves an on-chain zPass later.
6. For example, first create a function called `testZPass()` and in the scope of it, let’s use the `signCredential` method from ZPassSDK.
7. The `signCredential` method takes an argument as an object with fields:
   1. `data`: A credential object with properties and respective values same as defined in the deployed zPass program. Note that the name of each property must match the name of the field in the credential struct from the zPass program. The value must be in string type and appended with Aleo type suffix such as u32 in order to be able to parse correctly.
   2. `hashType`: Pick supported hash algorithm to use for hashing the data, type HashAlgorithm can be imported from zpass-sdk.
   3. `privateKey?`: An optional private key to switch using if the issuer account private key is not used during initialization of ZPassSDK.
8. `signCredential` will return an object that contains signature and hash in string type, signature will be required as one of the inputs later during proveOffChain, proveOnChain or issueZPass.

```javascript
const { signature } = await sdk.signCredential({
    data: {
      issuer: "aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px",
      subject: "aleo172s23z4lw3z3ruwc92dgukq8s0v3249jg28zsldq6a0adpw7c5gqfnkla2",
      dob: "19990301u32",
      nationality: "2148979field",
      expiry: "20250301u32",
      salt: "231scalar"
    },
    hashType: HashAlgorithm.POSEIDON2
  }); 
```

9. After that, we can use the `issueZPass` method from ZPassSDK. Remember to initialize ZPassSDK before using its method.
10. The `issueZPass` method takes an argument as an object with fields:
    1. `programName`: The name of the program to call in string type, which is the name of a zPass program that has been deployed on-chain with the suffix of .aleo.
    2. `functionName`: The name of the calling function in string type.
    3. `privateFee`: To spend fee from private records or not, either true or false.
    4. `inputs`: An array of strings which are the inputs to the program function.
    5. `fee`: Fee to spend in microcredit, in number type.
    6. `feeRecord?`: Optional fee records to pass for program execution if privateFee is true.
11. The `issueZPass` method will return `transactionId` once successfully.
12. In our example, by following the parameters of issue transition in `verify_poseidon2_zpass.aleo` program this will be:

```javascript
const txId = await sdk.issueZPass({
    programName: "verify_poseidon2_zpass.aleo",
    functionName: "issue",
    privateFee: false,
    inputs: [
      signature,
      `{
        issuer: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px,
        subject: aleo172s23z4lw3z3ruwc92dgukq8s0v3249jg28zsldq6a0adpw7c5gqfnkla2,
        dob: 19990301u32,
        nationality: 2148979field,
        expiry: 20250301u32
      }`,
      `{
        salt: 231scalar
      }`
    ],
    fee: 3000,
}); 

```

13. Then return the `txId` back to the main application.&#x20;
14. To expose the `testZPass` function that we just created, use `expose` from `comlink` to expose it as a worker method like `expose({ testZPass })`; .

## Test running ZPass worker method

1. To try to run the `testZpass()` worker method that we just created, simply import `AleoWorker()` from `AleoWorker.js`, create an instant using `AleoWorker()` then call `testZPass()` method from that instant.
2. To test it in the local development network, check out how to set it up [here](https://developer.aleo.org/guides/leo/testing#local-testing-with-network).

```javascript
import { AleoWorker } from "./workers/AleoWorker.js";

const aleoWorker = AleoWorker();

const result = await aleoWorker.testZPass({
      privateKey: privateKey,
      host: hosturl
})
```


