Skip to main content

ZkVerifierClient

The ZkVerifierClient builds verification instructions for zero-knowledge proofs and queries on-chain proof contexts.
import { ZkVerifierClient, ProofType } from '@x0-protocol/sdk';

const zkVerifier = new ZkVerifierClient(connection);

Proof Types

ValueNameDescriptionProof Size
0PubkeyValidityProves an ElGamal public key is well-formed64 bytes
1WithdrawProves withdrawal amount is valid and balance remains non-negative160 bytes
2ZeroBalanceProves a ciphertext encrypts zero96 bytes
3TransferProves transfer amount is valid with range proof288 bytes

Verification Instructions

buildVerifyPubkeyValidityInstruction

const { instruction, proofContextPda } = zkVerifier.buildVerifyPubkeyValidityInstruction(
  ownerPubkey,
  tokenAccountPubkey,
  mintPubkey,
  proofData,         // Uint8Array (64 bytes)
  elgamalPubkey,     // Uint8Array (32 bytes)
  timestamp          // number
);

buildVerifyWithdrawInstruction

const { instruction, proofContextPda } = zkVerifier.buildVerifyWithdrawInstruction(
  ownerPubkey,
  tokenAccountPubkey,
  mintPubkey,
  proofData,               // Uint8Array (160 bytes)
  amount,                  // BN
  newDecryptableBalance,   // Uint8Array (36 bytes)
  timestamp
);

buildVerifyZeroBalanceInstruction

const { instruction, proofContextPda } = zkVerifier.buildVerifyZeroBalanceInstruction(
  ownerPubkey,
  tokenAccountPubkey,
  mintPubkey,
  proofData,     // Uint8Array (96 bytes)
  timestamp
);

buildVerifyTransferInstruction

const { instruction, proofContextPda } = zkVerifier.buildVerifyTransferInstruction(
  ownerPubkey,
  tokenAccountPubkey,
  mintPubkey,
  proofData,     // Uint8Array (288 bytes)
  amount,        // BN
  recipientPubkey,
  timestamp
);

Querying Proof Contexts

fetchProofContext(proofContextAddress)

const ctx = await zkVerifier.fetchProofContext(proofContextPda);
Returns: ProofContext | null
FieldTypeDescription
versionnumberContext version
proofTypeProofTypeType of proof verified
verifiedbooleanWhether the proof passed
ownerPublicKeyAccount owner
verifiedAtnumberVerification timestamp
amountBN | nullAmount (for withdraw/transfer proofs)
recipientPublicKey | nullRecipient (for transfer proofs)
elgamalPubkeyUint8Array | nullPublic key (for pubkey validity proofs)
mintPublicKeyToken mint
tokenAccountPublicKeyToken account
bumpnumberPDA bump

isProofFresh(proofContext)

Check if a proof context is still within the 5-minute freshness window:
if (!zkVerifier.isProofFresh(ctx)) {
  // Re-generate and verify proof
}

PDA Derivation

deriveProofContextPda(owner, tokenAccount, timestamp)

const [pda, bump] = zkVerifier.deriveProofContextPda(
  ownerPubkey,
  tokenAccountPubkey,
  timestamp
);

Usage with ConfidentialClient

In typical usage, the ConfidentialClient handles proof generation and verification internally. Use ZkVerifierClient directly when you need:
  • Custom proof verification logic
  • Batch proof verification
  • Proof context inspection
  • Integration with other on-chain programs
import { ConfidentialClient, ZkVerifierClient } from '@x0-protocol/sdk';

// High-level (recommended)
const confidential = new ConfidentialClient(connection, wallet);
await confidential.withdraw(tokenAccount, mint, BigInt(1000), keypair);

// Low-level (direct verification)
const zkVerifier = new ZkVerifierClient(connection);
const { instruction } = zkVerifier.buildVerifyWithdrawInstruction(
  owner, tokenAccount, mint, proofData, amount, newBalance, timestamp
);
Last modified on February 8, 2026