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 System | Base CU | Per Input CU | Max CU |
|---|---|---|---|
| Groth16 | 45,000 | 1,200 | 200,000 |
| PLONK | 68,000 | 1,800 | 350,000 |
| Halo2 | 92,000 | 2,400 | 500,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 malformed0x1002: PairingCheckFailed - Cryptographic verification failed0x1003: PublicInputMismatch - Input count doesn't match circuit0x1004: 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(())
}