Denisijcu commited on
Commit
6acaa0b
·
verified ·
1 Parent(s): 0e6831d
Files changed (3) hide show
  1. app/core/config.py +0 -0
  2. app/core/engine.py +73 -0
  3. app/core/security.py +0 -0
app/core/config.py ADDED
File without changes
app/core/engine.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from typing import List
3
+ from app.api.schemas.telemetry import KeystrokeData
4
+ from fastapi import HTTPException
5
+
6
+ class DECI_Engine:
7
+ def __init__(self):
8
+ self.MIN_KEYSTROKES = 25 # [cite: 5, 52]
9
+ self.WEIGHTS = {"entropy": 0.35, "cv": 0.30, "mean": 0.15, "corrections": 0.20} # [cite: 5, 101]
10
+
11
+ def process_session(self, events: List[KeystrokeData]) -> dict:
12
+ if len(events) < self.MIN_KEYSTROKES:
13
+ return {"verdict": "INCONCLUSIVE", "reason": f"Need {self.MIN_KEYSTROKES} keys"}
14
+
15
+ # Extraer intervalos compatibles con v2.0 [cite: 5, 111]
16
+ timestamps = np.array([float(e.timestamp) for e in events])
17
+ intervals = np.diff(timestamps)
18
+ intervals = intervals[intervals > 0]
19
+
20
+ # 1. Shannon Entropy Normalizada (Fixed by Claude) [cite: 5, 111]
21
+ entropy = self._compute_shannon_entropy(intervals)
22
+
23
+ # 2. Coeficiente de Variación (CV) [cite: 5, 111]
24
+ cv = np.std(intervals) / np.mean(intervals) if len(intervals) > 0 else 0
25
+
26
+ # 3. Burst Correction Ratio [cite: 5, 59]
27
+ burst_ratio = self._compute_burst_ratio(events)
28
+
29
+ # ── Scoring Multi-señal (Vertex Elite Logic) ──
30
+ # Entropy Goldilocks Zone [cite: 5, 59]
31
+ s_entropy = 1.0 if 0.50 <= entropy <= 0.85 else (0.5 if 0.35 <= entropy <= 0.95 else 0.05)
32
+ s_cv = 1.0 if cv > 0.50 else (0.6 if cv > 0.30 else 0.1)
33
+
34
+ # Mean IKL Scoring
35
+ mean_ms = np.mean(intervals)
36
+ s_mean = 1.0 if 60 <= mean_ms <= 500 else 0.2
37
+
38
+ # Correction Scoring con Bonus de Ráfaga [cite: 5, 59]
39
+ corr_rate = sum(1 for e in events if e.key == 'Backspace') / len(events)
40
+ s_corrections = (0.5 + burst_ratio * 0.5) if 0.02 <= corr_rate <= 0.15 else 0.2
41
+
42
+ # Weighted Final Score
43
+ final_score = float(np.clip(
44
+ s_entropy * self.WEIGHTS["entropy"] +
45
+ s_cv * self.WEIGHTS["cv"] +
46
+ s_mean * self.WEIGHTS["mean"] +
47
+ s_corrections * self.WEIGHTS["corrections"], 0.0, 1.0
48
+ ))
49
+
50
+ return {
51
+ "score": round(final_score, 4),
52
+ "verdict": "HUMAN" if final_score >= 0.65 else ("SUSPECT" if final_score >= 0.40 else "BOT"), #
53
+ "is_human": final_score >= 0.65,
54
+ "breakdown": {"entropy": round(entropy, 4), "cv": round(cv, 4), "burst": round(burst_ratio, 4)}
55
+ }
56
+
57
+ def _compute_shannon_entropy(self, intervals, bins=20):
58
+ hist, _ = np.histogram(intervals, bins=bins, density=True)
59
+ hist += 1e-10
60
+ raw_entropy = -np.sum(hist * np.log2(hist)) * (intervals.max() - intervals.min()) / bins
61
+ return float(np.clip(raw_entropy / np.log2(bins), 0.0, 1.0))
62
+
63
+ def _compute_burst_ratio(self, events):
64
+ # Detecta ráfagas de 3+ correcciones (comportamiento humano) [cite: 5, 59]
65
+ streak = burst = total = 0
66
+ for e in events:
67
+ if e.key == 'Backspace':
68
+ streak += 1
69
+ total += 1
70
+ else:
71
+ if streak >= 3: burst += streak
72
+ streak = 0
73
+ return float(burst / max(total, 1))
app/core/security.py ADDED
File without changes