Files
wifi-densepose/vendor/ruvector/examples/edge/pkg/zk-financial-proofs.ts

426 lines
12 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Zero-Knowledge Financial Proofs
*
* Prove financial statements without revealing actual numbers.
* All proof generation happens in the browser - private data never leaves.
*
* @example
* ```typescript
* import { ZkFinancialProver, ZkProofVerifier } from './zk-financial-proofs';
*
* // Prover (you - with private data)
* const prover = new ZkFinancialProver();
* prover.loadIncome([650000, 650000, 680000]); // cents
* prover.loadBalances([500000, 520000, 480000, 510000]);
*
* // Generate proof: "My income is at least 3x the rent"
* const proof = await prover.proveAffordability(200000, 3); // $2000 rent
*
* // Share proof with landlord (contains NO actual numbers)
* const proofJson = JSON.stringify(proof);
*
* // Verifier (landlord - without your private data)
* const result = ZkProofVerifier.verify(proofJson);
* console.log(result.valid); // true
* console.log(result.statement); // "Income ≥ 3× monthly rent of $2000"
* ```
*/
import init, {
ZkFinancialProver as WasmProver,
ZkProofVerifier as WasmVerifier,
ZkUtils,
} from './ruvector_edge';
// ============================================================================
// Types
// ============================================================================
/**
* A zero-knowledge proof
*/
export interface ZkProof {
proof_type: ProofType;
proof_data: number[];
public_inputs: PublicInputs;
generated_at: number;
expires_at?: number;
}
export type ProofType =
| 'Range'
| 'Comparison'
| 'Affordability'
| 'NonNegative'
| 'SumBound'
| 'AverageBound'
| 'SetMembership';
export interface PublicInputs {
commitments: Commitment[];
bounds: number[];
statement: string;
attestation?: Attestation;
}
export interface Commitment {
point: number[];
}
export interface Attestation {
issuer: string;
signature: number[];
timestamp: number;
}
export interface VerificationResult {
valid: boolean;
statement: string;
verified_at: number;
error?: string;
}
export interface RentalApplicationProof {
income_proof: ZkProof;
stability_proof: ZkProof;
savings_proof?: ZkProof;
metadata: ApplicationMetadata;
}
export interface ApplicationMetadata {
applicant_id: string;
property_id?: string;
generated_at: number;
expires_at: number;
}
// ============================================================================
// Prover (Client-Side)
// ============================================================================
/**
* Generate zero-knowledge proofs about financial data.
*
* All proof generation happens locally in WebAssembly.
* Your actual financial numbers are NEVER revealed.
*/
export class ZkFinancialProver {
private wasmProver: WasmProver | null = null;
private initialized = false;
/**
* Initialize the prover
*/
async init(): Promise<void> {
if (this.initialized) return;
await init();
this.wasmProver = new WasmProver();
this.initialized = true;
}
/**
* Load monthly income data
* @param monthlyIncome Array of monthly income in CENTS (e.g., $6500 = 650000)
*/
loadIncome(monthlyIncome: number[]): void {
this.ensureInit();
this.wasmProver!.loadIncome(new BigUint64Array(monthlyIncome.map(BigInt)));
}
/**
* Load expense data for a category
* @param category Category name (e.g., "Food", "Transportation")
* @param monthlyExpenses Array of monthly expenses in CENTS
*/
loadExpenses(category: string, monthlyExpenses: number[]): void {
this.ensureInit();
this.wasmProver!.loadExpenses(category, new BigUint64Array(monthlyExpenses.map(BigInt)));
}
/**
* Load daily balance history
* @param dailyBalances Array of daily balances in CENTS (can be negative)
*/
loadBalances(dailyBalances: number[]): void {
this.ensureInit();
this.wasmProver!.loadBalances(new BigInt64Array(dailyBalances.map(BigInt)));
}
// --------------------------------------------------------------------------
// Proof Generation
// --------------------------------------------------------------------------
/**
* Prove: average income ≥ threshold
*
* Use case: Prove you make at least $X without revealing exact income
*
* @param thresholdDollars Minimum income threshold in dollars
*/
async proveIncomeAbove(thresholdDollars: number): Promise<ZkProof> {
this.ensureInit();
const thresholdCents = Math.round(thresholdDollars * 100);
return this.wasmProver!.proveIncomeAbove(BigInt(thresholdCents));
}
/**
* Prove: income ≥ multiplier × rent
*
* Use case: Prove affordability for apartment application
*
* @param rentDollars Monthly rent in dollars
* @param multiplier Required income multiplier (typically 3)
*/
async proveAffordability(rentDollars: number, multiplier: number): Promise<ZkProof> {
this.ensureInit();
const rentCents = Math.round(rentDollars * 100);
return this.wasmProver!.proveAffordability(BigInt(rentCents), BigInt(multiplier));
}
/**
* Prove: no overdrafts in the past N days
*
* Use case: Prove account stability
*
* @param days Number of days to prove (e.g., 90)
*/
async proveNoOverdrafts(days: number): Promise<ZkProof> {
this.ensureInit();
return this.wasmProver!.proveNoOverdrafts(days);
}
/**
* Prove: current savings ≥ threshold
*
* Use case: Prove you have emergency fund
*
* @param thresholdDollars Minimum savings in dollars
*/
async proveSavingsAbove(thresholdDollars: number): Promise<ZkProof> {
this.ensureInit();
const thresholdCents = Math.round(thresholdDollars * 100);
return this.wasmProver!.proveSavingsAbove(BigInt(thresholdCents));
}
/**
* Prove: average spending in category ≤ budget
*
* Use case: Prove budgeting discipline
*
* @param category Spending category
* @param budgetDollars Maximum budget in dollars
*/
async proveBudgetCompliance(category: string, budgetDollars: number): Promise<ZkProof> {
this.ensureInit();
const budgetCents = Math.round(budgetDollars * 100);
return this.wasmProver!.proveBudgetCompliance(category, BigInt(budgetCents));
}
/**
* Prove: debt-to-income ratio ≤ max%
*
* Use case: Prove creditworthiness
*
* @param monthlyDebtDollars Monthly debt payments in dollars
* @param maxRatioPercent Maximum DTI ratio (e.g., 30 for 30%)
*/
async proveDebtRatio(monthlyDebtDollars: number, maxRatioPercent: number): Promise<ZkProof> {
this.ensureInit();
const debtCents = Math.round(monthlyDebtDollars * 100);
return this.wasmProver!.proveDebtRatio(BigInt(debtCents), BigInt(maxRatioPercent));
}
/**
* Create complete rental application proof bundle
*
* Includes all proofs typically needed for rental application
*
* @param rentDollars Monthly rent
* @param incomeMultiplier Required income multiple (usually 3)
* @param stabilityDays Days of no overdrafts to prove
* @param savingsMonths Months of rent to prove in savings (optional)
*/
async createRentalApplication(
rentDollars: number,
incomeMultiplier: number = 3,
stabilityDays: number = 90,
savingsMonths?: number
): Promise<RentalApplicationProof> {
this.ensureInit();
const rentCents = Math.round(rentDollars * 100);
return this.wasmProver!.createRentalApplication(
BigInt(rentCents),
BigInt(incomeMultiplier),
stabilityDays,
savingsMonths !== undefined ? BigInt(savingsMonths) : undefined
);
}
private ensureInit(): void {
if (!this.initialized || !this.wasmProver) {
throw new Error('Prover not initialized. Call init() first.');
}
}
}
// ============================================================================
// Verifier (Can Run Anywhere)
// ============================================================================
/**
* Verify zero-knowledge proofs.
*
* Verifier learns ONLY that the statement is true.
* Actual numbers remain completely hidden.
*/
export class ZkProofVerifier {
private static initialized = false;
/**
* Initialize the verifier
*/
static async init(): Promise<void> {
if (this.initialized) return;
await init();
this.initialized = true;
}
/**
* Verify a single proof
*
* @param proof The proof to verify (as object or JSON string)
*/
static async verify(proof: ZkProof | string): Promise<VerificationResult> {
await this.init();
const proofJson = typeof proof === 'string' ? proof : JSON.stringify(proof);
return WasmVerifier.verify(proofJson);
}
/**
* Verify a rental application bundle
*/
static async verifyRentalApplication(
application: RentalApplicationProof | string
): Promise<{ all_valid: boolean; results: VerificationResult[] }> {
await this.init();
const appJson = typeof application === 'string' ? application : JSON.stringify(application);
return WasmVerifier.verifyRentalApplication(appJson);
}
/**
* Get human-readable statement from proof
*/
static async getStatement(proof: ZkProof | string): Promise<string> {
await this.init();
const proofJson = typeof proof === 'string' ? proof : JSON.stringify(proof);
return WasmVerifier.getStatement(proofJson);
}
/**
* Check if proof is expired
*/
static async isExpired(proof: ZkProof | string): Promise<boolean> {
await this.init();
const proofJson = typeof proof === 'string' ? proof : JSON.stringify(proof);
return WasmVerifier.isExpired(proofJson);
}
}
// ============================================================================
// Utilities
// ============================================================================
export const ZkProofUtils = {
/**
* Convert proof to shareable URL
*/
toShareableUrl(proof: ZkProof, baseUrl: string = window.location.origin): string {
const proofJson = JSON.stringify(proof);
return ZkUtils.proofToUrl(proofJson, baseUrl + '/verify');
},
/**
* Extract proof from URL parameter
*/
fromUrl(encoded: string): ZkProof {
const json = ZkUtils.proofFromUrl(encoded);
return JSON.parse(json);
},
/**
* Format proof for display
*/
formatProof(proof: ZkProof): string {
return `
┌─────────────────────────────────────────────────┐
│ Zero-Knowledge Proof │
├─────────────────────────────────────────────────┤
│ Type: ${proof.proof_type.padEnd(41)}
│ Statement: ${proof.public_inputs.statement.slice(0, 36).padEnd(36)}
│ Generated: ${new Date(proof.generated_at * 1000).toLocaleDateString().padEnd(36)}
│ Expires: ${proof.expires_at ? new Date(proof.expires_at * 1000).toLocaleDateString().padEnd(38) : 'Never'.padEnd(38)}
│ Proof size: ${(proof.proof_data.length + ' bytes').padEnd(35)}
└─────────────────────────────────────────────────┘
`.trim();
},
/**
* Calculate proof size in bytes
*/
proofSize(proof: ZkProof): number {
return JSON.stringify(proof).length;
},
};
// ============================================================================
// Presets for Common Use Cases
// ============================================================================
/**
* Pre-configured proof generators for common scenarios
*/
export const ZkPresets = {
/**
* Standard rental application (3x income, 90 days stability, 2 months savings)
*/
async rentalApplication(
prover: ZkFinancialProver,
monthlyRent: number
): Promise<RentalApplicationProof> {
return prover.createRentalApplication(monthlyRent, 3, 90, 2);
},
/**
* Loan pre-qualification (income above threshold, DTI under 30%)
*/
async loanPrequalification(
prover: ZkFinancialProver,
minimumIncome: number,
monthlyDebt: number
): Promise<{ incomeProof: ZkProof; dtiProof: ZkProof }> {
const incomeProof = await prover.proveIncomeAbove(minimumIncome);
const dtiProof = await prover.proveDebtRatio(monthlyDebt, 30);
return { incomeProof, dtiProof };
},
/**
* Employment verification (income above minimum)
*/
async employmentVerification(
prover: ZkFinancialProver,
minimumSalary: number
): Promise<ZkProof> {
return prover.proveIncomeAbove(minimumSalary);
},
/**
* Account stability (no overdrafts for 6 months)
*/
async accountStability(prover: ZkFinancialProver): Promise<ZkProof> {
return prover.proveNoOverdrafts(180);
},
};
export default { ZkFinancialProver, ZkProofVerifier, ZkProofUtils, ZkPresets };