Instruction Set

Complete reference for all ZKVAULT Solana program instructions with detailed parameter specifications and execution semantics.

Instruction Architecture

ZKVAULT program instructions follow Anchor framework conventions with deterministic instruction discriminators and structured account metadata.

Instruction Discriminator Format

// 8-byte discriminator derived from Sighash
discriminator = SHA256("global:instruction_name")[0..8]

// Example for VerifyProof
VerifyProof discriminator: [0x3a, 0x69, 0x67, 0x12, 0x8f, 0x4d, 0x2b, 0xc1]

InitVault

Initialize a new encrypted vault with zero-knowledge proof verification capabilities.

Instruction Data

pub struct InitVault {
    pub vault_id: [u8; 32],           // Unique vault identifier
    pub proof_system_type: u8,        // 0: Groth16, 1: PLONK, 2: Halo2
    pub verification_key_hash: [u8; 32],
    pub max_data_size: u64,           // Maximum encrypted data size
    pub access_control: AccessControl,
}

pub enum AccessControl {
    Owner,                             // Only vault owner
    Whitelist { addresses: Vec<Pubkey> },
    Public,                           // Anyone can verify
}

Accounts

#[derive(Accounts)]
pub struct InitVault<'info> {
    #[account(
        init,
        payer = authority,
        space = 8 + Vault::SIZE,
        seeds = [b"vault", authority.key().as_ref(), &vault_id],
        bump
    )]
    pub vault: Account<'info, Vault>,
    
    #[account(mut)]
    pub authority: Signer<'info>,
    
    pub system_program: Program<'info, System>,
}

Validation Rules

  • vault_id must be unique per authority
  • max_data_size ≤ 10MB (Solana account limit)
  • verification_key_hash must match proof_system_type
  • Rent-exempt minimum must be met

SubmitProof

Submit a zero-knowledge proof for on-chain verification with associated public inputs.

Instruction Data

pub struct SubmitProof {
    pub proof_bytes: Vec<u8>,         // Compressed proof (192-256 bytes)
    pub public_inputs: Vec<u64>,      // Public circuit inputs
    pub metadata: ProofMetadata,
}

pub struct ProofMetadata {
    pub circuit_id: [u8; 32],         // Circuit identifier
    pub prover_address: Pubkey,       // Proof generator
    pub timestamp: i64,
    pub nonce: u64,                   // Replay protection
}

Accounts

#[derive(Accounts)]
pub struct SubmitProof<'info> {
    #[account(
        init,
        payer = prover,
        space = 8 + ProofSubmission::SIZE,
        seeds = [b"proof", vault.key().as_ref(), &nonce.to_le_bytes()],
        bump
    )]
    pub proof_submission: Account<'info, ProofSubmission>,
    
    #[account(mut)]
    pub vault: Account<'info, Vault>,
    
    #[account(mut)]
    pub prover: Signer<'info>,
    
    pub system_program: Program<'info, System>,
}

Compute Unit Requirements

Proof SystemBase CUPer Input CUMax CU
Groth1645,0001,200200,000
PLONK68,0001,800350,000
Halo292,0002,400500,000

VerifyProof

Execute cryptographic verification of a submitted proof against the vault's verification key.

Instruction Data

pub struct VerifyProof {
    pub proof_id: Pubkey,             // Reference to ProofSubmission
    pub expected_result: bool,        // Optional: expected verification result
}

Verification Algorithm

// Simplified verification flow
fn verify_proof(
    proof: &[u8],
    public_inputs: &[u64],
    vk: &VerificationKey,
) -> Result<bool> {
    // 1. Deserialize proof components
    let (pi_a, pi_b, pi_c) = deserialize_proof(proof)?;
    
    // 2. Prepare public input encoding
    let input_encoding = encode_inputs(public_inputs)?;
    
    // 3. Pairing check (Groth16)
    let lhs = pairing(&pi_a, &pi_b);
    let rhs = pairing(&vk.alpha, &vk.beta) 
            + pairing(&input_encoding, &vk.gamma)
            + pairing(&pi_c, &vk.delta);
    
    // 4. Verify equation: e(A, B) = e(α, β) · e(inputs, γ) · e(C, δ)
    Ok(lhs == rhs)
}

Error Codes

  • 0x1001: InvalidProofFormat - Proof bytes malformed
  • 0x1002: PairingCheckFailed - Cryptographic verification failed
  • 0x1003: PublicInputMismatch - Input count doesn't match circuit
  • 0x1004: ProofExpired - Timestamp exceeds validity window

StoreEncryptedData

Store encrypted data in a vault with zero-knowledge proof of correct encryption.

Instruction Data

pub struct StoreEncryptedData {
    pub encrypted_data: Vec<u8>,      // ChaCha20-Poly1305 ciphertext
    pub encryption_proof: Vec<u8>,    // Proof of correct encryption
    pub data_commitment: [u8; 32],    // Pedersen commitment to plaintext
    pub metadata: DataMetadata,
}

pub struct DataMetadata {
    pub content_type: String,         // MIME type
    pub encryption_timestamp: i64,
    pub access_policy_hash: [u8; 32],
}

Size Constraints

  • Maximum encrypted_data: 10 KB per instruction
  • For larger data: Use multiple StoreEncryptedData calls with chunking
  • Each chunk must include chunk_index and total_chunks in metadata

ReadEncryptedData

Retrieve encrypted data with optional zero-knowledge proof of authorization.

Instruction Data

pub struct ReadEncryptedData {
    pub data_id: [u8; 32],            // Data identifier
    pub access_proof: Option<Vec<u8>>, // ZK proof of read permission
    pub requester: Pubkey,
}

Access Control Flow

// Access verification logic
match vault.access_control {
    AccessControl::Owner => {
        require!(requester == vault.authority, Unauthorized);
    }
    AccessControl::Whitelist { ref addresses } => {
        require!(addresses.contains(&requester), Unauthorized);
    }
    AccessControl::Public => {
        // Anyone can read
    }
    AccessControl::ProofBased => {
        // Verify access_proof demonstrates authorization
        let proof_valid = verify_access_proof(
            access_proof.as_ref().unwrap(),
            &requester,
            &vault.access_policy
        )?;
        require!(proof_valid, InvalidAccessProof);
    }
}

UpdateVerificationKey

Update the vault's verification key for circuit upgrades (requires authority).

Instruction Data

pub struct UpdateVerificationKey {
    pub new_vk_hash: [u8; 32],
    pub new_vk_data: Vec<u8>,         // Serialized verification key
    pub migration_proof: Vec<u8>,     // Proof of valid migration
}

CloseVault

Close and deallocate a vault, returning rent to authority.

Safety Checks

  • Vault must be empty (no pending proofs)
  • All encrypted data must be explicitly deleted first
  • Requires authority signature
  • Emits VaultClosed event for off-chain indexing

Cross-Program Invocation (CPI) Support

ZKVAULT instructions can be invoked from other Solana programs via CPI for composable privacy.

use anchor_lang::prelude::*;
use zkvault::program::Zkvault;
use zkvault::cpi::accounts::VerifyProof;
use zkvault::cpi;

pub fn call_zkvault_verify(ctx: Context<CallZkVault>, proof: Vec<u8>) -> Result<()> {
    let cpi_accounts = VerifyProof {
        vault: ctx.accounts.vault.to_account_info(),
        proof_submission: ctx.accounts.proof.to_account_info(),
        authority: ctx.accounts.authority.to_account_info(),
    };
    
    let cpi_ctx = CpiContext::new(
        ctx.accounts.zkvault_program.to_account_info(),
        cpi_accounts,
    );
    
    cpi::verify_proof(cpi_ctx, proof)?;
    Ok(())
}