名称: 零知识证明缓存
描述: 用于缓存ZK证明以提升性能,实现证明缓存失效机制,存储验证结果,缓存中间证明组件,或使用Redis构建分布式证明缓存。
证明缓存
缓存证明和证明组件,以提高证明生成服务的性能并减少冗余计算。
使用场景
- 缓存验证结果以避免重复验证相同证明
- 存储生成的证明以供潜在重用
- 缓存中间证明组件
- 实现基于TTL的证明过期机制
- 使用Redis构建分布式证明缓存
核心概念
可缓存内容
| 组件 |
是否可缓存? |
TTL注意事项 |
| 验证结果 |
是 |
长(证明不可变) |
| 生成的证明 |
视情况而定 |
短(状态可能变化) |
| 电路密钥 |
是 |
直到合约更新 |
| 见证模板 |
有时 |
取决于使用场景 |
缓存键设计
良好的证明缓存键应能唯一标识证明:
// 用于验证结果
function verificationCacheKey(
circuitId: string,
proofHash: string,
publicInputsHash: string
): string {
return `verify:${circuitId}:${proofHash}:${publicInputsHash}`;
}
// 用于生成的证明
function proofCacheKey(
circuitId: string,
witnessHash: string
): string {
return `proof:${circuitId}:${witnessHash}`;
}
缓存失效
| 场景 |
失效策略 |
| 合约升级 |
清除电路的所有证明 |
| 状态变更 |
清除依赖变更状态的证明 |
| TTL过期 |
自动移除 |
| 手动清除 |
管理员触发的清除 |
参考资料
示例
快速开始
1. 简单内存缓存
import { LRUCache } from 'lru-cache';
import { createHash } from 'crypto';
const verificationCache = new LRUCache<string, boolean>({
max: 10000,
ttl: 1000 * 60 * 60, // 1小时
});
function hashData(data: unknown): string {
return createHash('sha256')
.update(JSON.stringify(data))
.digest('hex');
}
async function verifyWithCache(
circuitId: string,
proof: Uint8Array,
publicInputs: Record<string, unknown>
): Promise<boolean> {
const key = `${circuitId}:${hashData(proof)}:${hashData(publicInputs)}`;
// 检查缓存
const cached = verificationCache.get(key);
if (cached !== undefined) {
return cached;
}
// 验证
const result = await verifier.verify(circuitId, proof, publicInputs);
// 缓存结果
verificationCache.set(key, result.valid);
return result.valid;
}
2. 基于Redis的分布式缓存
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
async function verifyWithRedisCache(
circuitId: string,
proof: Uint8Array,
publicInputs: Record<string, unknown>
): Promise<boolean> {
const key = `verify:${circuitId}:${hashData(proof)}:${hashData(publicInputs)}`;
// 检查缓存
const cached = await redis.get(key);
if (cached !== null) {
return cached === 'true';
}
// 验证
const result = await verifier.verify(circuitId, proof, publicInputs);
// 缓存1小时TTL
await redis.setex(key, 3600, result.valid ? 'true' : 'false');
return result.valid;
}
常见模式
多级缓存
class MultiLevelProofCache {
private l1: LRUCache<string, boolean>; // 内存
private l2: Redis; // Redis
constructor(redis: Redis) {
this.l1 = new LRUCache({ max: 1000, ttl: 60000 });
this.l2 = redis;
}
async get(key: string): Promise<boolean | undefined> {
// 检查L1
const l1Result = this.l1.get(key);
if (l1Result !== undefined) {
return l1Result;
}
// 检查L2
const l2Result = await this.l2.get(key);
if (l2Result !== null) {
const value = l2Result === 'true';
this.l1.set(key, value); // 填充L1
return value;
}
return undefined;
}
async set(key: string, value: boolean, ttlSeconds: number): Promise<void> {
this.l1.set(key, value);
await this.l2.setex(key, ttlSeconds, value ? 'true' : 'false');
}
}
缓存旁路模式
async function verifyProofCacheAside(
circuitId: string,
proof: Uint8Array,
publicInputs: Record<string, unknown>
): Promise<boolean> {
const key = buildCacheKey(circuitId, proof, publicInputs);
// 1. 尝试缓存
const cached = await cache.get(key);
if (cached !== undefined) {
metrics.cacheHit();
return cached;
}
metrics.cacheMiss();
// 2. 计算
const result = await verifier.verify(circuitId, proof, publicInputs);
// 3. 存储到缓存
await cache.set(key, result.valid, 3600);
return result.valid;
}
批量缓存查找
async function verifyBatchWithCache(
proofs: ProofItem[]
): Promise<Map<string, boolean>> {
const results = new Map<string, boolean>();
const uncached: ProofItem[] = [];
// 构建键
const keys = proofs.map((p) => buildCacheKey(p.circuitId, p.proof, p.publicInputs));
// 批量缓存查找
const cachedValues = await redis.mget(keys);
// 分离已缓存和未缓存
proofs.forEach((proof, i) => {
if (cachedValues[i] !== null) {
results.set(proof.id, cachedValues[i] === 'true');
} else {
uncached.push(proof);
}
});
// 验证未缓存的
if (uncached.length > 0) {
const verifyResults = await verifyBatch(uncached);
// 缓存新结果
const pipeline = redis.pipeline();
uncached.forEach((proof, i) => {
const key = buildCacheKey(proof.circuitId, proof.proof, proof.publicInputs);
pipeline.setex(key, 3600, verifyResults[i] ? 'true' : 'false');
results.set(proof.id, verifyResults[i]);
});
await pipeline.exec();
}
return results;
}
缓存预热
async function warmCache(circuitIds: string[]): Promise<void> {
console.log('预热缓存电路:', circuitIds);
for (const circuitId of circuitIds) {
// 预生成常见证明
const commonWitnesses = await getCommonWitnesses(circuitId);
for (const witness of commonWitnesses) {
try {
const proof = await prover.prove(circuitId, witness);
const key = buildProofCacheKey(circuitId, witness);
await cache.set(key, proof, 3600);
} catch (error) {
console.warn(`为${circuitId}预热缓存失败:`, error);
}
}
}
console.log('缓存预热完成');
}
缓存指标
class CacheMetrics {
private hits = 0;
private misses = 0;
private evictions = 0;
hit(): void {
this.hits++;
}
miss(): void {
this.misses++;
}
evict(): void {
this.evictions++;
}
getStats(): {
hits: number;
misses: number;
hitRate: number;
evictions: number;
} {
const total = this.hits + this.misses;
return {
hits: this.hits,
misses: this.misses,
hitRate: total > 0 ? this.hits / total : 0,
evictions: this.evictions,
};
}
}
性能考虑
| 关注点 |
缓解措施 |
| 缓存雪崩 |
使用锁或概率性提前过期 |
| 内存压力 |
设置合适的最大大小,使用LRU淘汰 |
| 陈旧数据 |
设置合适的TTL,实现失效机制 |
| 网络延迟(Redis) |
使用连接池,多级缓存 |
相关技能
proof-generation - 生成要缓存的证明
proof-verification - 使用缓存验证证明
prover-optimization - 优化证明生成
相关命令
当前未定义。