Back to Documentation
> ADVANCED

Advanced Topics

Custom circuits, performance optimization, and troubleshooting

Custom Circuits

Create custom zkSNARK circuits for specialized privacy requirements.

Circuit Development

// Example: Custom range proof circuit
use zkprime_circuits::{Circuit, ConstraintSystem};

pub struct RangeProofCircuit {
    value: Option<u64>,
    min: u64,
    max: u64,
}

impl Circuit for RangeProofCircuit {
    fn synthesize<CS: ConstraintSystem>(
        self,
        cs: &mut CS,
    ) -> Result<(), SynthesisError> {
        // Allocate value as private witness
        let value = cs.alloc_input(|| {
            self.value.ok_or(SynthesisError::AssignmentMissing)
        })?;
        
        // Constrain: min <= value <= max
        cs.enforce_constraint(
            value.clone(),
            LinearCombination::from(self.min),
            ConstraintType::GreaterOrEqual,
        )?;
        
        cs.enforce_constraint(
            value,
            LinearCombination::from(self.max),
            ConstraintType::LessOrEqual,
        )?;
        
        Ok(())
    }
}

Using Custom Circuits

import { ZKPrimeClient } from '@zkprime/sdk';

// Load custom circuit
const client = new ZKPrimeClient({ ... });
await client.loadCustomCircuit('range-proof', circuitWasm);

// Generate proof with custom circuit
const proof = await client.generateProof({
  circuit: 'range-proof',
  statement: 'value in range [100, 1000]',
  witness: { value: 500 }
});

Circuit Best Practices:

  • • Minimize constraint count for faster proving
  • • Use lookup tables for complex operations
  • • Test circuits thoroughly with edge cases
  • • Optimize for verification time (on-chain cost)

Performance Tuning

Proof Caching

Cache generated proofs to avoid regeneration for repeated operations

const client = new ZKPrimeClient({
  rpcUrl: '...',
  proofCaching: true,  // Enable proof caching
  cacheSize: 100,      // Cache last 100 proofs
});

// First call generates proof (~3s)
const proof1 = await client.generateProof(params);

// Subsequent calls retrieve from cache (~5ms)
const proof2 = await client.generateProof(params);

Batch Transactions

Process multiple transactions in a single proof for better throughput

// Batch multiple transfers
const batch = await client.createBatchTransfer({
  transfers: [
    { to: recipient1, amount: 100 },
    { to: recipient2, amount: 200 },
    { to: recipient3, amount: 300 },
  ],
  from: wallet,
});

// Single proof for all transfers (~4s total vs 9s individual)
const signature = await client.submitTransaction(batch);

Worker Threads

Offload proof generation to web workers for non-blocking UI

const client = new ZKPrimeClient({
  rpcUrl: '...',
  useWorkers: true,  // Enable web workers
  workerCount: 4,    // Use 4 parallel workers
});

// Proof generation happens in background
const proofPromise = client.generateProof(params);

// UI remains responsive
updateUI('Generating proof...');

const proof = await proofPromise;
updateUI('Proof complete!');

Performance Comparison

Standard (no optimization)~3.5s per tx
With caching~0.5s per tx
Batched (10 tx)~0.4s per tx

Troubleshooting

Issue: Proof Generation Fails

Error: "Constraint system unsatisfied"

Solutions:

• Verify witness data matches circuit constraints

• Check that all required fields are provided

• Ensure values are within expected ranges

• Enable debug mode: debug: true

Issue: Transaction Rejected On-Chain

Error: "Invalid proof" or "Nullifier already spent"

Solutions:

• Refresh commitment tree before generating proof

• Check that commitment hasn't been spent already

• Verify you're using correct network (devnet/mainnet)

• Increase transaction priority fee if timing out

Issue: Slow Proof Generation

Proof taking more than 10 seconds

Solutions:

• Enable web workers: useWorkers: true

• Use lower privacy level for testing

• Check device CPU capabilities

• Consider server-side proof generation

Issue: Cannot Decrypt Balance

Error: "Decryption failed" or returns wrong value

Solutions:

• Verify you're using correct private key

• Ensure encrypted state is for your address

• Check key derivation path matches

• Try re-syncing encrypted state

Debug Mode

Enable detailed logging for troubleshooting:

const client = new ZKPrimeClient({
  rpcUrl: '...',
  debug: true,
  logLevel: 'debug' // 'debug' | 'info' | 'warn' | 'error'
});

// Check console for detailed logs
// [ZKPrime:debug] Generating proof...
// [ZKPrime:debug] Circuit constraints: 1543
// [ZKPrime:debug] Witness data loaded
// [ZKPrime:info] Proof generated in 3.2s

Contributing

ZKPrime is open source and welcomes contributions from the community.

Code Contributions

  • • Fork the repository on GitHub
  • • Create feature branch
  • • Write tests for new features
  • • Submit pull request

Documentation

  • • Improve existing docs
  • • Write tutorials
  • • Add code examples
  • • Report documentation bugs