plugins/midnight-proofs/skills/proof-verification/SKILL.md
Use when verifying ZK proofs server-side, validating proofs before transaction submission, building verification gateways, implementing batch verification, or debugging proof generation issues.
npx skillsauth add aaronbassett/midnight-knowledgebase midnight-proofs:proof-verificationInstall 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.
Verify ZK proofs server-side before transaction submission to catch invalid proofs early and reduce failed transactions.
| Benefit | Description | |---------|-------------| | Fail fast | Catch invalid proofs before network submission | | Save gas | Avoid transaction fees for invalid proofs | | Better UX | Provide immediate feedback to users | | Security | Validate proofs from untrusted clients |
// Both verification and validation
async function verifyAndValidate(proof: Proof, publicInputs: PublicInputs): Promise<boolean> {
// Step 1: Cryptographic verification
const isValidProof = await verifier.verify(proof, publicInputs);
if (!isValidProof) return false;
// Step 2: Business validation
const isValidBusiness = validateBusinessRules(publicInputs);
return isValidBusiness;
}
Verification is much faster than proof generation:
| Operation | Typical Duration | |-----------|------------------| | Proof Generation | 5-30 seconds | | Proof Verification | 10-100 milliseconds |
| Document | Description | |----------|-------------| | verification-api.md | Verifier SDK setup and API reference |
| Example | Description | |---------|-------------| | pre-submit-validation/ | Verify before transaction submit | | batch-verification/ | Verify multiple proofs in parallel |
import { createVerifier } from '@midnight-ntwrk/midnight-js-verifier';
const verifier = await createVerifier({
verificationKeysPath: './circuit-keys',
});
async function verifyProof(
circuitId: string,
proof: Uint8Array,
publicInputs: Record<string, unknown>
): Promise<boolean> {
try {
const result = await verifier.verify(circuitId, proof, publicInputs);
return result.valid;
} catch (error) {
console.error('Verification failed:', error);
return false;
}
}
async function submitWithVerification(
transaction: Transaction
): Promise<string> {
// Extract proof and public inputs from transaction
const { proof, publicInputs, circuitId } = transaction;
// Verify first
const isValid = await verifyProof(circuitId, proof, publicInputs);
if (!isValid) {
throw new Error('Proof verification failed');
}
// Submit to network
return await submitTransaction(transaction);
}
import express from 'express';
const app = express();
app.post('/api/verify', async (req, res) => {
const { circuitId, proof, publicInputs } = req.body;
try {
const result = await verifier.verify(
circuitId,
Buffer.from(proof, 'base64'),
publicInputs
);
res.json({
valid: result.valid,
circuitId,
verificationTime: result.duration,
});
} catch (error) {
res.status(400).json({
valid: false,
error: error.message,
});
}
});
interface ProofBatch {
circuitId: string;
proof: Uint8Array;
publicInputs: Record<string, unknown>;
}
async function verifyBatch(
proofs: ProofBatch[]
): Promise<Map<number, boolean>> {
const results = new Map<number, boolean>();
// Verify in parallel
const verifications = proofs.map(async (p, index) => {
try {
const result = await verifier.verify(
p.circuitId,
p.proof,
p.publicInputs
);
results.set(index, result.valid);
} catch {
results.set(index, false);
}
});
await Promise.all(verifications);
return results;
}
import { createHash } from 'crypto';
const verifiedProofs = new Map<string, boolean>();
function proofHash(proof: Uint8Array, publicInputs: Record<string, unknown>): string {
const data = JSON.stringify({ proof: proof.toString(), publicInputs });
return createHash('sha256').update(data).digest('hex');
}
async function verifyWithCache(
circuitId: string,
proof: Uint8Array,
publicInputs: Record<string, unknown>
): Promise<boolean> {
const hash = proofHash(proof, publicInputs);
// Check cache
if (verifiedProofs.has(hash)) {
return verifiedProofs.get(hash)!;
}
// Verify
const result = await verifier.verify(circuitId, proof, publicInputs);
verifiedProofs.set(hash, result.valid);
return result.valid;
}
async function verifyWithTimeout(
circuitId: string,
proof: Uint8Array,
publicInputs: Record<string, unknown>,
timeoutMs = 5000
): Promise<boolean> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const result = await verifier.verify(circuitId, proof, publicInputs, {
signal: controller.signal,
});
return result.valid;
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Verification timeout');
}
throw error;
} finally {
clearTimeout(timeout);
}
}
enum VerificationError {
INVALID_PROOF = 'INVALID_PROOF',
INVALID_PUBLIC_INPUTS = 'INVALID_PUBLIC_INPUTS',
CIRCUIT_NOT_FOUND = 'CIRCUIT_NOT_FOUND',
MALFORMED_PROOF = 'MALFORMED_PROOF',
TIMEOUT = 'TIMEOUT',
}
function classifyVerificationError(error: Error): VerificationError {
if (error.message.includes('circuit')) {
return VerificationError.CIRCUIT_NOT_FOUND;
}
if (error.message.includes('public input')) {
return VerificationError.INVALID_PUBLIC_INPUTS;
}
if (error.message.includes('malformed')) {
return VerificationError.MALFORMED_PROOF;
}
if (error.message.includes('timeout')) {
return VerificationError.TIMEOUT;
}
return VerificationError.INVALID_PROOF;
}
| Concern | Mitigation | |---------|------------| | Verification key loading | Preload keys at startup | | High request volume | Use verification caching | | Large batches | Limit concurrent verifications | | Memory usage | Stream large proof batches |
proof-generation - Generate proofs server-sideproof-caching - Cache verification resultsprover-optimization - Optimize prover that creates proofsNone 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.