plugins/midnight-proofs/skills/proof-generation/SKILL.md
Use when generating ZK proofs server-side, building proof-as-a-service backends, offloading proof computation from clients, creating proof generation queues, or implementing async proof generation.
npx skillsauth add aaronbassett/midnight-knowledgebase midnight-proofs:proof-generationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate ZK proofs server-side to offload computation from client devices and build scalable proof-as-a-service backends.
| Aspect | Client-Side | Server-Side | |--------|-------------|-------------| | Privacy | Witness data stays local | Witness sent to server (encrypted) | | Latency | Limited by device power | Fast dedicated hardware | | Scalability | One proof at a time | Parallel proof generation | | Use Case | Privacy-critical apps | High-throughput services |
// Server-side proof generation overview
async function generateProof(request: ProofRequest): Promise<ProofResponse> {
const { circuitId, witness } = request;
// Load circuit proving key
const provingKey = await loadProvingKey(circuitId);
// Generate the proof (CPU intensive)
const proof = await prover.prove(provingKey, witness);
return { proof, circuitId };
}
Witness data contains private inputs to the circuit. When handling server-side:
| Document | Description | |----------|-------------| | prover-api.md | Prover SDK setup and API reference | | witness-formatting.md | Witness input structure and validation |
| Example | Description | |---------|-------------| | rest-endpoint/ | Express REST API for proof generation | | queue-worker/ | Redis queue-based proof worker |
import { createProver } from '@midnight-ntwrk/midnight-js-prover';
const prover = await createProver({
// Path to circuit proving keys
circuitKeysPath: './circuit-keys',
// Memory limit for proof generation
memoryLimit: 4096, // MB
});
import express from 'express';
const app = express();
app.use(express.json());
app.post('/api/prove', async (req, res) => {
const { circuitId, witness } = req.body;
try {
const proof = await prover.prove(circuitId, witness);
res.json({ success: true, proof: proof.toString('base64') });
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
// For long-running proofs, use async pattern
app.post('/api/prove/async', async (req, res) => {
const { circuitId, witness } = req.body;
// Create job ID
const jobId = crypto.randomUUID();
// Queue proof generation
await proofQueue.add({ jobId, circuitId, witness });
// Return immediately with job ID
res.json({ jobId, status: 'queued' });
});
// Poll for status
app.get('/api/prove/status/:jobId', async (req, res) => {
const job = await proofQueue.getJob(req.params.jobId);
if (!job) {
return res.status(404).json({ error: 'Job not found' });
}
if (job.status === 'completed') {
return res.json({ status: 'completed', proof: job.result });
}
res.json({ status: job.status });
});
import { z } from 'zod';
const ProofRequestSchema = z.object({
circuitId: z.string().min(1),
witness: z.record(z.unknown()),
timeout: z.number().optional().default(60000),
});
function validateProofRequest(body: unknown) {
return ProofRequestSchema.parse(body);
}
async function proveWithTimeout(
circuitId: string,
witness: WitnessData,
timeoutMs = 60000
): Promise<Proof> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
return await prover.prove(circuitId, witness, {
signal: controller.signal,
});
} finally {
clearTimeout(timeout);
}
}
app.get('/health', async (req, res) => {
try {
// Verify prover is ready
const isReady = await prover.isReady();
res.json({
status: isReady ? 'healthy' : 'degraded',
proverReady: isReady,
uptime: process.uptime(),
});
} catch (error) {
res.status(503).json({ status: 'unhealthy', error: error.message });
}
});
enum ProofErrorCode {
INVALID_WITNESS = 'INVALID_WITNESS',
CIRCUIT_NOT_FOUND = 'CIRCUIT_NOT_FOUND',
PROOF_GENERATION_FAILED = 'PROOF_GENERATION_FAILED',
TIMEOUT = 'TIMEOUT',
OUT_OF_MEMORY = 'OUT_OF_MEMORY',
}
class ProofError extends Error {
constructor(
public code: ProofErrorCode,
message: string,
public details?: unknown
) {
super(message);
this.name = 'ProofError';
}
}
| Concern | Mitigation | |---------|------------| | CPU-intensive proof generation | Use worker threads or separate processes | | Memory spikes during proving | Set memory limits, monitor usage | | Long request timeouts | Use async job queue pattern | | Circuit key loading time | Pre-load keys at startup |
proof-verification - Verify generated proofsproof-caching - Cache proof components for performanceprover-optimization - Tune prover for production workloadsNone currently defined.
tools
Use when setting up Midnight development environment, installing Compact compiler and developer tools, configuring proof server, verifying prerequisites, or getting started with Midnight development.
tools
--- name: midnight-tooling:midnight-debugging description: Use when encountering Midnight errors like "compact: command not found", "ERR_UNSUPPORTED_DIR_IMPORT", version mismatches, proof server failures, "@midnight-ntwrk" package errors, or compilation failures. --- # Midnight Environment Debugging Expert knowledge for identifying and resolving common Midnight development toolchain issues. ## Diagnostic Approach When encountering Midnight-related errors, follow this systematic approach: 1.
tools
Use when checking Midnight version compatibility, understanding pragma language_version, verifying compiler and runtime version relationships, or troubleshooting version mismatch errors between Midnight components.
tools
Use when setting up CI/CD for Midnight projects, configuring GitHub Actions for Compact contract compilation, running TypeScript tests in CI, validating version consistency, or automating contract builds.