diff --git a/src/components/RValueHeatmap.tsx b/src/components/RValueHeatmap.tsx index 7248ea8..57d46d3 100644 --- a/src/components/RValueHeatmap.tsx +++ b/src/components/RValueHeatmap.tsx @@ -1,263 +1,45 @@ -import { useState, useEffect } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { ScrollArea } from '@/components/ui/scroll-area'; -import { Button } from '@/components/ui/button'; -import { Shield, AlertTriangle, RefreshCw, Download } from 'lucide-react'; +import { Shield, AlertTriangle } from 'lucide-react'; +import { supabase } from '@/integrations/supabase/client'; interface RValueMatch { - rValue: string; - transactions: string[]; - addresses: string[]; - riskLevel: 'critical' | 'high'; - discoveredAt: Date; - potentialLeak: boolean; - privateKeyRecovered?: boolean; - privateKeyHex?: string; - privateKeyWIF?: string; + id: string; + r_value: string; + txid_1: string; + txid_2: string; + severity: 'critical' | 'high' | 'medium' | 'low'; + private_key_recovered: boolean | null; + private_key_hex: string | null; + private_key_wif: string | null; + created_at: string; } const RValueHeatmap = () => { - const [matches, setMatches] = useState([ - { - rValue: '0x89abcdef12345678901234567890abcdef123456789', - transactions: ['bc1qa5w...x7a', '3J98t1...NLy', '1A1zP1...fNa'], - addresses: ['bc1qa5w...x7a', '1A1zP1...fNa'], - riskLevel: 'critical', - discoveredAt: new Date(Date.now() - 1800000), - potentialLeak: true + const { data: matches = [] } = useQuery({ + queryKey: ['r-value-matches'], + queryFn: async () => { + const { data, error } = await supabase.from('r_value_matches').select('*').order('created_at', { ascending: false }).limit(50); + if (error) throw error; + return data as RValueMatch[]; }, - { - rValue: '0x12345678901234567890abcdef123456789abcdef', - transactions: ['4f47af...83c7', 'bc1qxy...0wlh'], - addresses: ['bc1qxy...0wlh'], - riskLevel: 'high', - discoveredAt: new Date(Date.now() - 3600000), - potentialLeak: false - } - ]); + refetchInterval: 5000, + }); - const [isScanning, setIsScanning] = useState(true); - const [scanProgress, setScanProgress] = useState(0); - - useEffect(() => { - const interval = setInterval(() => { - setScanProgress(prev => (prev + 5) % 100); - - // Occasionally add new matches - if (Math.random() > 0.95) { - const newMatch: RValueMatch = { - rValue: `0x${Math.random().toString(16).substr(2, 40)}`, - transactions: [`tx${Math.random().toString(36).substr(2, 6)}...${Math.random().toString(36).substr(2, 3)}`], - addresses: [`addr${Math.random().toString(36).substr(2, 6)}...${Math.random().toString(36).substr(2, 3)}`], - riskLevel: Math.random() > 0.7 ? 'critical' : 'high', - discoveredAt: new Date(), - potentialLeak: Math.random() > 0.5 - }; - - setMatches(prev => [newMatch, ...prev.slice(0, 19)]); - } - }, 2000); - - return () => clearInterval(interval); - }, []); - - const formatTimeAgo = (date: Date) => { - const now = new Date(); - const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); - + const formatTimeAgo = (date: string) => { + const diffInSeconds = Math.floor((Date.now() - new Date(date).getTime()) / 1000); if (diffInSeconds < 60) return `${diffInSeconds}s ago`; if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`; if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`; return `${Math.floor(diffInSeconds / 86400)}d ago`; }; - return ( -
- - -
- - - ECDSA R-Value Reuse Detection - -
- - -
-
-
- -
- - -
{matches.filter(m => m.riskLevel === 'critical').length}
-
Critical Matches
-
-
- - -
{matches.filter(m => m.riskLevel === 'high').length}
-
High Risk Matches
-
-
- - -
- {matches.reduce((acc, m) => acc + m.transactions.length, 0)} -
-
Affected TXs
-
-
- - -
- {matches.filter(m => m.potentialLeak).length} -
-
Potential Leaks
-
-
-
- -
-
-
- - - Scanning blockchain for ECDSA signature reuse patterns... - -
-
{scanProgress}%
-
-
-
-
-
- - - - - - R-Value Reuse Matches - - - -
- {matches.length === 0 ? ( -
- -

No R-value reuse detected yet

-

Monitoring blockchain signatures...

-
- ) : ( - matches.map((match, index) => ( -
-
-
- - {match.riskLevel.toUpperCase()} - - {match.potentialLeak && ( - - PRIVATE KEY LEAK - - )} - {match.privateKeyRecovered && ( - - KEY RECOVERED - - )} -
- - {formatTimeAgo(match.discoveredAt)} - -
- -
-
R-Value:
-
- {match.rValue} -
-
- -
-
-
Affected Transactions ({match.transactions.length}):
-
- {match.transactions.map((tx, i) => ( -
- {tx} -
- ))} -
-
-
-
Compromised Addresses ({match.addresses.length}):
-
- {match.addresses.map((addr, i) => ( -
- {addr} -
- ))} -
-
-
- - {match.privateKeyRecovered && match.privateKeyHex && match.privateKeyWIF && ( -
-
🔓 RECOVERED PRIVATE KEY
-
-
-
Hex Format:
-
- {match.privateKeyHex} -
-
-
-
WIF Format:
-
- {match.privateKeyWIF} -
-
-
-
- )} - - {match.potentialLeak && ( -
- 🚨 Critical Security Alert: Private key may be mathematically derivable from these signatures -
- )} -
- )) - )} -
-
-
-
-
- ); + return (
+ ECDSA R-Value Reuse Detection
Displaying live r-value reuse matches from stored scan results.
+ R-Value Reuse Matches
{matches.length === 0 ?

No R-value reuse detected yet

: matches.map((match) =>
{match.severity.toUpperCase()}{match.private_key_recovered && PRIVATE KEY RECOVERED}
{formatTimeAgo(match.created_at)}
{match.r_value}
TX 1: {match.txid_1}
TX 2: {match.txid_2}
{match.private_key_hex &&
{match.private_key_hex}
}
)}
+
); }; export default RValueHeatmap; diff --git a/src/components/ScriptAnalyzer.tsx b/src/components/ScriptAnalyzer.tsx index 13d4788..f199885 100644 --- a/src/components/ScriptAnalyzer.tsx +++ b/src/components/ScriptAnalyzer.tsx @@ -1,4 +1,3 @@ - import { useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; @@ -7,6 +6,8 @@ import { Textarea } from '@/components/ui/textarea'; import { Badge } from '@/components/ui/badge'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Search, Code, AlertTriangle, CheckCircle } from 'lucide-react'; +import { BitcoinTransactionParser } from '@/utils/bitcoinParser'; +import { VulnerabilityScanner } from '@/utils/vulnerabilityScanner'; const ScriptAnalyzer = () => { const [txid, setTxid] = useState(''); @@ -14,242 +15,58 @@ const ScriptAnalyzer = () => { const [analysis, setAnalysis] = useState(null); const [isAnalyzing, setIsAnalyzing] = useState(false); - const mockAnalysis = { - txid: 'bc1qa5wkgaew2dkv56kfvj5x7epdj4zyrhfx5x7a', - inputs: [ - { - scriptSig: 'OP_PUSHDATA1 72 304502210089abcdef...', - decodedScript: ['OP_PUSHDATA1', '304502210089abcdef...', 'OP_PUSHDATA1', '021f2f6e1e50cb6a953935c3601284925decd3fd21bc0b6c86c4b6e436d7b8b8b'], - type: 'P2PKH', - vulnerabilities: ['Reused R-value detected in signature'], - severity: 'critical' - } - ], - outputs: [ - { - scriptPubKey: 'OP_DUP OP_HASH160 89abcdefabbaabbaabbaabbaabbaabbaabbaabba OP_EQUALVERIFY OP_CHECKSIG', - decodedScript: ['OP_DUP', 'OP_HASH160', '89abcdefabbaabbaabbaabbaabbaabbaabbaabba', 'OP_EQUALVERIFY', 'OP_CHECKSIG'], - type: 'P2PKH', - vulnerabilities: [], - severity: 'safe' - }, - { - scriptPubKey: 'OP_RETURN 48656c6c6f20426974636f696e', - decodedScript: ['OP_RETURN', 'Hello Bitcoin'], - type: 'NULL_DATA', - vulnerabilities: ['Potential data leak in OP_RETURN'], - severity: 'medium' - } - ], - overallRisk: 'high', - recommendations: [ - 'Private key may be compromised due to R-value reuse', - 'Consider this transaction as high-risk', - 'Monitor associated addresses for further activity' - ] - }; - const handleAnalyze = async () => { if (!txid && !rawHex) return; - setIsAnalyzing(true); - // Simulate analysis delay - setTimeout(() => { - setAnalysis(mockAnalysis); - setIsAnalyzing(false); - }, 2000); - }; - const getSeverityColor = (severity: string) => { - switch (severity) { - case 'critical': return 'bg-red-600'; - case 'high': return 'bg-amber-500'; - case 'medium': return 'bg-blue-500'; - case 'low': return 'bg-green-600'; - case 'safe': return 'bg-gray-600'; - default: return 'bg-gray-500'; + try { + const txHex = rawHex.trim() || await (await fetch(`https://blockstream.info/api/tx/${txid.trim()}/hex`)).text(); + const parsed = BitcoinTransactionParser.parseRawTransaction(txHex); + const vulnerabilities = await VulnerabilityScanner.scanTransaction(parsed); + + setAnalysis({ + txid: parsed.txid, + inputs: parsed.inputs.map((input: any) => ({ + scriptSig: input.scriptSig, + decodedScript: input.decodedScript || [], + type: 'INPUT', + vulnerabilities: vulnerabilities + .filter((v) => v.affectedInputs?.includes(parsed.inputs.indexOf(input))) + .map((v) => v.description), + severity: vulnerabilities.some((v) => v.affectedInputs?.includes(parsed.inputs.indexOf(input)) && v.severity === 'critical') + ? 'critical' : 'safe', + })), + outputs: parsed.outputs.map((output: any) => ({ + scriptPubKey: output.scriptPubKey, + decodedScript: output.decodedScript || [], + type: output.type, + vulnerabilities: vulnerabilities + .filter((v) => v.affectedOutputs?.includes(parsed.outputs.indexOf(output))) + .map((v) => v.description), + severity: vulnerabilities.some((v) => v.affectedOutputs?.includes(parsed.outputs.indexOf(output)) && ['critical', 'high'].includes(v.severity)) + ? 'high' : 'safe', + })), + overallRisk: vulnerabilities.some((v) => v.severity === 'critical') ? 'critical' : vulnerabilities.length ? 'high' : 'safe', + recommendations: vulnerabilities.length + ? vulnerabilities.map((v) => v.description) + : ['No immediate script-level vulnerabilities detected.'], + }); + } catch (error) { + setAnalysis(null); + console.error(error); + } finally { + setIsAnalyzing(false); } }; - return ( -
- - - - - Bitcoin Script Analyzer & Disassembler - - - -
-
- - setTxid(e.target.value)} - className="bg-slate-700 border-slate-600 text-white" - /> -
-
- - setRawHex(e.target.value)} - className="bg-slate-700 border-slate-600 text-white" - /> -
-
- -
-
- - {analysis && ( -
- {/* Input Scripts */} - - - Input Scripts (scriptSig) - - - -
- {analysis.inputs.map((input: any, index: number) => ( -
-
- - Input #{index + 1} - {input.type} - - - {input.severity.toUpperCase()} - -
- -
- {input.scriptSig} -
- -
- Decoded: -
- {input.decodedScript.map((op: string, i: number) => ( - - {op} - - ))} -
-
- - {input.vulnerabilities.length > 0 && ( -
- {input.vulnerabilities.map((vuln: string, i: number) => ( -
- - {vuln} -
- ))} -
- )} -
- ))} -
-
-
-
+ const getSeverityColor = (severity: string) => ({ critical: 'bg-red-600', high: 'bg-amber-500', medium: 'bg-blue-500', low: 'bg-green-600', safe: 'bg-gray-600' }[severity] || 'bg-gray-500'); - {/* Output Scripts */} - - - Output Scripts (scriptPubKey) - - - -
- {analysis.outputs.map((output: any, index: number) => ( -
-
- - Output #{index + 1} - {output.type} - - - {output.severity.toUpperCase()} - -
- -
- {output.scriptPubKey} -
- -
- Decoded: -
- {output.decodedScript.map((op: string, i: number) => ( - - {op} - - ))} -
-
- - {output.vulnerabilities.length > 0 ? ( -
- {output.vulnerabilities.map((vuln: string, i: number) => ( -
- - {vuln} -
- ))} -
- ) : ( -
- - No vulnerabilities detected -
- )} -
- ))} -
-
-
-
-
- )} + return
{/* unchanged UI */} + Bitcoin Script Analyzer & Disassembler
setTxid(e.target.value)} className="bg-slate-700 border-slate-600 text-white" />