Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,584 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ZK Financial Proofs Demo - RuVector Edge</title>
<style>
:root {
--bg: #0a0a0f;
--card: #12121a;
--border: #2a2a3a;
--text: #e0e0e8;
--text-dim: #8888a0;
--accent: #8b5cf6;
--accent-glow: rgba(139, 92, 246, 0.3);
--success: #22c55e;
--warning: #f59e0b;
--error: #ef4444;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--bg);
color: var(--text);
min-height: 100vh;
line-height: 1.6;
}
.container { max-width: 1200px; margin: 0 auto; padding: 2rem; }
header { text-align: center; margin-bottom: 3rem; }
h1 {
font-size: 2.5rem;
background: linear-gradient(135deg, var(--accent), #ec4899);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.subtitle { color: var(--text-dim); font-size: 1.1rem; margin-top: 0.5rem; }
.privacy-badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
background: rgba(139, 92, 246, 0.1);
border: 1px solid rgba(139, 92, 246, 0.3);
color: var(--accent);
padding: 0.5rem 1rem;
border-radius: 2rem;
margin-top: 1rem;
font-size: 0.9rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 1rem;
padding: 1.5rem;
}
.card h2 {
font-size: 1.2rem;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.form-group { margin-bottom: 1rem; }
label {
display: block;
font-size: 0.9rem;
color: var(--text-dim);
margin-bottom: 0.25rem;
}
input, select {
background: var(--bg);
border: 1px solid var(--border);
color: var(--text);
padding: 0.75rem;
border-radius: 0.5rem;
font-size: 1rem;
width: 100%;
}
input:focus, select:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-glow);
}
button {
background: var(--accent);
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
font-size: 1rem;
cursor: pointer;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 20px var(--accent-glow);
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
button.secondary {
background: transparent;
border: 1px solid var(--border);
color: var(--text);
}
.proof-display {
background: var(--bg);
border: 1px solid var(--border);
border-radius: 0.5rem;
padding: 1rem;
font-family: 'Fira Code', monospace;
font-size: 0.85rem;
white-space: pre-wrap;
word-break: break-all;
max-height: 300px;
overflow-y: auto;
}
.verification-result {
padding: 1rem;
border-radius: 0.5rem;
margin-top: 1rem;
}
.verification-result.valid {
background: rgba(34, 197, 94, 0.1);
border: 1px solid rgba(34, 197, 94, 0.3);
}
.verification-result.invalid {
background: rgba(239, 68, 68, 0.1);
border: 1px solid rgba(239, 68, 68, 0.3);
}
.flow-diagram {
background: var(--bg);
border: 1px solid var(--border);
border-radius: 0.5rem;
padding: 1.5rem;
text-align: center;
margin-bottom: 1.5rem;
}
.flow-step {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
background: var(--card);
border-radius: 0.5rem;
margin: 0 0.25rem;
}
.flow-arrow {
color: var(--text-dim);
font-size: 1.5rem;
}
.tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
}
.tab {
padding: 0.5rem 1rem;
background: transparent;
border: 1px solid var(--border);
color: var(--text-dim);
cursor: pointer;
border-radius: 0.5rem;
}
.tab.active {
background: var(--accent);
border-color: var(--accent);
color: white;
}
.hidden { display: none; }
.info-box {
background: rgba(139, 92, 246, 0.05);
border: 1px solid rgba(139, 92, 246, 0.2);
border-radius: 0.5rem;
padding: 1rem;
margin-bottom: 1rem;
font-size: 0.9rem;
}
footer {
text-align: center;
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid var(--border);
color: var(--text-dim);
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🔐 Zero-Knowledge Financial Proofs</h1>
<p class="subtitle">Prove financial statements without revealing actual numbers</p>
<div class="privacy-badge">
🛡️ Your actual income, balance, and transactions are NEVER revealed
</div>
</header>
<!-- Flow Diagram -->
<div class="flow-diagram">
<span class="flow-step">📊 Your Private Data</span>
<span class="flow-arrow"></span>
<span class="flow-step">🔮 ZK Circuit (WASM)</span>
<span class="flow-arrow"></span>
<span class="flow-step">📜 Proof (~1KB)</span>
<span class="flow-arrow"></span>
<span class="flow-step">✅ Verifier</span>
</div>
<div class="grid">
<!-- Prover Panel -->
<div class="card">
<h2>👤 Prover (Your Data - Private)</h2>
<div class="info-box">
<strong>How it works:</strong> Enter your real financial data below.
The ZK system will generate a proof that ONLY reveals the statement is true,
not your actual numbers.
</div>
<div class="form-group">
<label>Monthly Income ($)</label>
<input type="number" id="income" value="6500" placeholder="e.g., 6500">
</div>
<div class="form-group">
<label>Current Savings ($)</label>
<input type="number" id="savings" value="15000" placeholder="e.g., 15000">
</div>
<div class="form-group">
<label>Monthly Rent ($)</label>
<input type="number" id="rent" value="2000" placeholder="e.g., 2000">
</div>
<div class="form-group">
<label>Proof Type</label>
<select id="proof-type">
<option value="affordability">Rental Affordability (Income ≥ 3× Rent)</option>
<option value="income">Income Above Threshold</option>
<option value="savings">Savings Above Threshold</option>
<option value="no-overdraft">No Overdrafts (90 days)</option>
<option value="full-application">Complete Rental Application</option>
</select>
</div>
<button id="generate-btn" onclick="generateProof()">
🔮 Generate ZK Proof
</button>
<div id="prover-result" style="margin-top: 1rem;"></div>
</div>
<!-- Verifier Panel -->
<div class="card">
<h2>🏢 Verifier (Landlord/Bank - No Private Data)</h2>
<div class="info-box">
<strong>What verifier sees:</strong> Only the proof and statement.
Cannot determine actual income, savings, or any other numbers.
</div>
<div class="tabs">
<button class="tab active" onclick="showTab('paste')">Paste Proof</button>
<button class="tab" onclick="showTab('received')">Received Proof</button>
</div>
<div id="tab-paste">
<div class="form-group">
<label>Proof JSON</label>
<textarea id="proof-input" class="proof-display" rows="8"
placeholder="Paste proof JSON here..."></textarea>
</div>
</div>
<div id="tab-received" class="hidden">
<div class="proof-display" id="received-proof">
No proof received yet. Generate one from the Prover panel.
</div>
</div>
<button onclick="verifyProof()">
✅ Verify Proof
</button>
<div id="verification-result"></div>
</div>
<!-- What's Proven vs Hidden -->
<div class="card">
<h2>🔍 What's Proven vs What's Hidden</h2>
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="border-bottom: 1px solid var(--border);">
<th style="padding: 0.5rem; text-align: left;">Statement</th>
<th style="padding: 0.5rem; text-align: center;">Proven</th>
<th style="padding: 0.5rem; text-align: center;">Hidden</th>
</tr>
</thead>
<tbody id="proof-breakdown">
<tr>
<td style="padding: 0.5rem;">Income ≥ 3× Rent</td>
<td style="padding: 0.5rem; text-align: center; color: var(--success);">✓ Yes/No</td>
<td style="padding: 0.5rem; text-align: center; color: var(--error);">🔒 Exact amount</td>
</tr>
</tbody>
</table>
<div style="margin-top: 1rem; padding: 1rem; background: var(--bg); border-radius: 0.5rem;">
<strong>Privacy Guarantee:</strong>
<p style="color: var(--text-dim); margin-top: 0.5rem; font-size: 0.9rem;">
The verifier mathematically CANNOT extract your actual numbers from the proof.
They only learn whether the statement is true or false.
</p>
</div>
</div>
<!-- Use Cases -->
<div class="card">
<h2>💡 Real-World Use Cases</h2>
<div style="display: flex; flex-direction: column; gap: 1rem;">
<div style="padding: 1rem; background: var(--bg); border-radius: 0.5rem;">
<strong>🏠 Rental Applications</strong>
<p style="color: var(--text-dim); font-size: 0.9rem;">
Prove you can afford rent without revealing exact salary
</p>
</div>
<div style="padding: 1rem; background: var(--bg); border-radius: 0.5rem;">
<strong>💳 Credit Applications</strong>
<p style="color: var(--text-dim); font-size: 0.9rem;">
Prove debt-to-income ratio without revealing all debts
</p>
</div>
<div style="padding: 1rem; background: var(--bg); border-radius: 0.5rem;">
<strong>💼 Employment Verification</strong>
<p style="color: var(--text-dim); font-size: 0.9rem;">
Prove you earn above minimum without revealing exact pay
</p>
</div>
<div style="padding: 1rem; background: var(--bg); border-radius: 0.5rem;">
<strong>🏦 Account Stability</strong>
<p style="color: var(--text-dim); font-size: 0.9rem;">
Prove no overdrafts without revealing transaction history
</p>
</div>
</div>
</div>
</div>
<footer>
<p>Powered by <strong>RuVector Edge</strong> • Bulletproofs-style ZK Proofs • 100% Browser-Local</p>
</footer>
</div>
<script type="module">
// Simulated ZK proof generation (in production, uses WASM)
let lastProof = null;
window.generateProof = async function() {
const btn = document.getElementById('generate-btn');
btn.disabled = true;
btn.innerHTML = '⏳ Generating...';
const income = parseFloat(document.getElementById('income').value);
const savings = parseFloat(document.getElementById('savings').value);
const rent = parseFloat(document.getElementById('rent').value);
const proofType = document.getElementById('proof-type').value;
// Simulate proof generation
await new Promise(r => setTimeout(r, 500));
let statement, canProve;
switch (proofType) {
case 'affordability':
canProve = income >= rent * 3;
statement = `Income ≥ 3× monthly rent of $${rent}`;
break;
case 'income':
canProve = income >= 5000;
statement = `Average monthly income ≥ $5,000`;
break;
case 'savings':
canProve = savings >= rent * 2;
statement = `Current savings ≥ $${rent * 2}`;
break;
case 'no-overdraft':
canProve = savings > 0;
statement = `No overdrafts in the past 90 days`;
break;
case 'full-application':
canProve = income >= rent * 3 && savings >= rent * 2;
statement = `Complete rental application for $${rent}/month`;
break;
}
if (!canProve) {
document.getElementById('prover-result').innerHTML = `
<div style="color: var(--error); padding: 1rem; background: rgba(239,68,68,0.1); border-radius: 0.5rem;">
❌ Cannot generate proof: Your data doesn't meet the requirement.
<br><small>Actual numbers never leave your browser.</small>
</div>
`;
btn.disabled = false;
btn.innerHTML = '🔮 Generate ZK Proof';
return;
}
// Generate proof structure
lastProof = {
proof_type: proofType === 'affordability' ? 'Affordability' : 'Range',
proof_data: Array.from({length: 256}, () => Math.floor(Math.random() * 256)),
public_inputs: {
commitments: [{
point: Array.from({length: 32}, () => Math.floor(Math.random() * 256))
}],
bounds: [rent * 100, 3],
statement: statement,
},
generated_at: Math.floor(Date.now() / 1000),
expires_at: Math.floor(Date.now() / 1000) + 86400 * 30,
};
const proofJson = JSON.stringify(lastProof, null, 2);
document.getElementById('prover-result').innerHTML = `
<div style="color: var(--success); margin-bottom: 0.5rem;">
✅ Proof generated successfully!
</div>
<div class="proof-display" style="max-height: 200px;">
${proofJson}
</div>
<button class="secondary" style="margin-top: 0.5rem;" onclick="copyProof()">
📋 Copy Proof
</button>
`;
document.getElementById('received-proof').textContent = proofJson;
document.getElementById('proof-input').value = proofJson;
updateBreakdown(income, savings, rent, proofType);
btn.disabled = false;
btn.innerHTML = '🔮 Generate ZK Proof';
};
window.verifyProof = function() {
const proofJson = document.getElementById('proof-input').value ||
document.getElementById('received-proof').textContent;
if (!proofJson || proofJson.includes('No proof')) {
alert('Please generate or paste a proof first');
return;
}
try {
const proof = JSON.parse(proofJson);
// Simulate verification
const result = {
valid: true,
statement: proof.public_inputs.statement,
verified_at: Math.floor(Date.now() / 1000),
};
document.getElementById('verification-result').innerHTML = `
<div class="verification-result ${result.valid ? 'valid' : 'invalid'}">
<h3>${result.valid ? '✅ Proof Valid' : '❌ Proof Invalid'}</h3>
<p style="margin-top: 0.5rem;"><strong>Statement:</strong> ${result.statement}</p>
<p style="margin-top: 0.5rem; color: var(--text-dim); font-size: 0.9rem;">
${result.valid
? 'The prover has demonstrated the statement is TRUE without revealing actual values.'
: 'The proof could not be verified.'}
</p>
</div>
`;
} catch (e) {
document.getElementById('verification-result').innerHTML = `
<div class="verification-result invalid">
<h3>❌ Invalid Proof Format</h3>
<p>${e.message}</p>
</div>
`;
}
};
window.copyProof = function() {
const proofJson = JSON.stringify(lastProof);
navigator.clipboard.writeText(proofJson);
alert('Proof copied to clipboard!');
};
window.showTab = function(tab) {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelector(`[onclick="showTab('${tab}')"]`).classList.add('active');
document.getElementById('tab-paste').classList.toggle('hidden', tab !== 'paste');
document.getElementById('tab-received').classList.toggle('hidden', tab !== 'received');
};
function updateBreakdown(income, savings, rent, proofType) {
const tbody = document.getElementById('proof-breakdown');
const rows = {
'affordability': [
['Income ≥ 3× Rent', '✓ True/False', '🔒 $' + income.toLocaleString()],
['Rent amount', '✓ $' + rent.toLocaleString(), '—'],
],
'income': [
['Income ≥ $5,000', '✓ True/False', '🔒 $' + income.toLocaleString()],
],
'savings': [
['Savings ≥ $' + (rent * 2).toLocaleString(), '✓ True/False', '🔒 $' + savings.toLocaleString()],
],
'no-overdraft': [
['No overdrafts (90 days)', '✓ True/False', '🔒 All balances'],
],
'full-application': [
['Income ≥ 3× Rent', '✓ True/False', '🔒 $' + income.toLocaleString()],
['No overdrafts', '✓ True/False', '🔒 All balances'],
['Savings ≥ 2× Rent', '✓ True/False', '🔒 $' + savings.toLocaleString()],
],
};
tbody.innerHTML = (rows[proofType] || rows['affordability']).map(([stmt, proven, hidden]) => `
<tr>
<td style="padding: 0.5rem;">${stmt}</td>
<td style="padding: 0.5rem; text-align: center; color: var(--success);">${proven}</td>
<td style="padding: 0.5rem; text-align: center; color: var(--error);">${hidden}</td>
</tr>
`).join('');
}
// Initialize
updateBreakdown(6500, 15000, 2000, 'affordability');
</script>
</body>
</html>