Offline Facial Recognition + 10-Layer Liveness Detection for NHAI Datalake 3.0
| Version | 1.0.0 |
| Hackathon | NHAI Innovation Hackathon 7.0 |
| Target | Android 8.0+ / iOS 12+, ≥ 3 GB RAM, mid-range CPUs |
| Footprint | 14.67 MB models · APK 41.83 MB (arm64) / 92.45 MB (universal) / 34.15 MB (armv7) |
| Latency | 27–33 ms per frame, < 1 s end-to-end |
| Accuracy | 99.48% LFW (paper), 12/12 spoof vectors rejected on device |
| License | MIT (code) + Apache-2.0 (models). No NC, no ND. |
- Offline-first. Every frame is processed on-device. The network is only used to push 512-byte embeddings after the user has been authenticated and approved. A working NetraEdge device is useful even on a flight.
- Defense in depth. No single liveness signal is trusted. Ten independent layers must all pass (or be vetoed by a stronger signal) before the user is declared live. Photos, replays, masks, deepfakes, and 3D prints each fail at least 3 layers.
- Privacy by default. The face image never leaves the device. The 128-d embedding is Laplace-noised (ε=1.0, sensitivity=2.0) before transmission. The local cache is auto-purged on sync ack. The audit log is the only persistent record and is signed.
- State-aware fusion. Liveness is a temporal decision, not a per-frame one. An EMA (α=0.15) smooths the 10-layer signal over time. A 3-second grace period at the start of every verify session prevents motion-blurred first frames from being flagged SPOOF.
- Honest engineering. Models are pre-trained Apache-2.0 weights (MobileFaceNet, MediaPipe, MiniFASNet). No custom training. No fabricated benchmarks. The
benchmarks/real_*.jsonfiles contain raw measured data; the on-device numbers in the README are the production targets.
NETRAEDGE 1.0.0
┌──────────────────────────────────────────────────────────────────────┐
│ │
│ ┌────────────┐ ┌─────────────┐ ┌────────────┐ ┌──────────┐ │
│ │ CameraX │──▶│ MediaPipe │──▶│ FaceAlign │──▶│ TFLite │ │
│ │ Image │ │ Face Land- │ │ 5-pt Sim. │ │ GPU │ │
│ │ Analysis │ │ marker │ │ Transf. │ │ Delegate │ │
│ └─────┬──────┘ │ 468 lm + 52 │ │ + CLAHE │ │ (FP16) │ │
│ │ │ blendshapes │ └──────┬─────┘ └────┬─────┘ │
│ │ └──────┬─────┘ │ │ │
│ │ │ │ │ │
│ │ │ 112×112×3 RGB face crop │
│ │ │ │ │ │
│ │ ▼ ▼ ▼ │
│ │ ┌─────────────────────────────────────────────┐ │
│ │ │ 128-d L2-normalized 10-layer fusion │ │
│ │ │ embedding (cosine) L1…L10 │ │
│ │ └─────────────────┬──────────────────────────┘ │
│ │ │ │
│ │ ┌────────────┴─────────────┐ │
│ │ ▼ ▼ │
│ │ ┌────────────┐ ┌─────────────┐ │
│ │ │ Matching │ │ Spoof / │ │
│ │ │ Engine │ │ Live │ │
│ │ │ cosine≥0.62│ │ Decision │ │
│ │ └─────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌──────────────────────────────────────────┐ │
│ │ │ Decision: VERIFIED | SPOOF | NOT_RECOG │ │
│ │ └──────────┬───────────────────────────────┘ │
│ │ │ │
│ │ ┌────────┴────────┐ │
│ │ ▼ ▼ │
│ │ ┌──────────┐ ┌─────────────┐ │
│ │ │ Encrypted│ │ SyncManager │ │
│ │ │ Local │ │ (offline │ │
│ │ │ Cache │ │ queue) │ │
│ │ │ AES-256- │ └──────┬──────┘ │
│ │ │ GCM │ │ │
│ │ └──────────┘ ▼ │
│ │ Datalake 3.0 │
│ │ AWS ap-south-1 │
│ │ │
│ ──────┴──────────────────────────────────────────────── │
│ Sensor layer: TYPE_ROTATION_VECTOR + TYPE_ACCELEROMETER │
│ (L7 Sensor Fusion — detects device stillness during replay) │
│ │
└──────────────────────────────────────────────────────────────────┘
flowchart TB
subgraph DEVICE["MOBILE DEVICE (offline-first)"]
CAM[CameraX<br/>ImageAnalysis] --> MP[MediaPipe<br/>Face Landmarker<br/>468 lm + 52 blendshapes]
SENS[Gyro + Accel] --> SF[Sensor Fusion L7]
MP --> ALN[FaceAligner<br/>5-pt + CLAHE]
ALN -->|112×112×3| TFR[Face Recognition<br/>MobileFaceNet TFLite GPU]
ALN -->|112×112×3| TL1[Passive CNN L1]
MP -->|blendshapes| CH[Active Challenge L9]
MP -->|cheek ROI| RP[rPPG POS L10]
TFR --> EM[128-d L2-normalised<br/>embedding]
TL1 --> FUS{10-Layer Fusion<br/>EMA α=0.15}
SF --> FUS
CH --> FUS
RP --> FUS
FUS --> DEC{Decision Engine}
EM --> MATCH{cosine ≥ 0.62?}
DEC -->|VERIFIED + SPOOF + NOT_RECOGNIZED| UI[Status Card + Face Overlay]
MATCH -->|match| UI
EM -.->|no match| DEC
end
UI --> CACHE[(Encrypted Local Cache<br/>AES-256-GCM)]
CACHE --> SYNC[SyncManager<br/>+ Laplace DP noise<br/>ε=1.0, Δf=2.0]
SYNC -->|HTTPS TLS 1.3| AWS[(NHAI Datalake 3.0<br/>AWS ap-south-1)]
AWS -->|200 OK| PURGE[Auto-purge local cache]
PURGE --> AUDIT[(Signed Audit Log<br/>7-year retention)]
Liveness architecture — read this carefully. All 10 layers in the shipped v1.0.0 are algorithmic (not model-based). The
liveness_detector.tflite(MiniFASNet, 0.52 MB) is loaded into the APK but bypassed at the spoof decision; it is kept as a backup / future-toggle for A/B testing on Indian demographics. The shipped verdict comes entirely from the 10 algorithmic layers below.
| # | Layer | Technique | Latency | Catches |
|---|---|---|---|---|
| 1 | Texture | LBP histogram (Local Binary Patterns) | 0.3 ms | Print surface vs skin (paper grain) |
| 2 | Color distribution | HSV skew + luma entropy | 0.3 ms | Printed photos, monochrome surfaces |
| 3 | Moiré pattern | Radix-2 FFT, 0.05–0.5 cycles/px | 0.4 ms | LCD/AMOLED screen replays |
| 4 | Specular highlights | Laplacian-of-Gaussian over forehead | 0.2 ms | Plastic masks, mannequins |
| 5 | Light consistency | Left/right cheek luma delta (≤ 0.15) | 0.2 ms | Mask asymmetry, unnatural lighting |
| 6 | Temporal consistency | Optical-flow magnitude between frames | 0.4 ms | Static single-frame attacks |
| 7 | Sensor fusion | Gyro+accel magnitude; replay ⇒ stillness | 0.05 ms | Device stillness during replay attack |
| 8 | Banding | Gradient histogram in 8-bit buckets | 0.3 ms | Compressed video playback |
| 9 | Active challenge | BLINK / SMILE / HEAD_TURN_LEFT / HEAD_TURN_RIGHT | real-time | Static photos, willing colluders |
| 10 | rPPG pulse | POS algorithm (Wang 2016), 8-s window | 0.4 ms | Printouts, plaster, no-pulse surfaces |
stateDiagram-v2
[*] --> IDLE
IDLE --> VERIFYING: onVerifyClicked<br/>(reset lastShownChallengeStep)
VERIFYING --> GRACE: 3-second grace period<br/>(no vetoes fire)
GRACE --> EVALUATING: 3 s elapsed
EVALUATING --> SPOOF: any veto (rPPG / screen /<br/>active-FAILED)
EVALUATING --> SPOOF: EMA score < 0.25<br/>after 3 s
EVALUATING --> VERIFIED: EMA score ≥ 0.25<br/>+ active passed<br/>+ cosine ≥ 0.62
VERIFYING --> NOT_RECOGNIZED: no enrolled embedding
VERIFYING --> NOT_RECOGNIZED: 10 s no-face timeout
VERIFYING --> SPOOF: challenge timeout 25 s
SPOOF --> IDLE: click handler resets
VERIFIED --> IDLE: click handler resets
NOT_RECOGNIZED --> IDLE: click handler resets
ENROLLED --> IDLE: click handler resets
Direct vetoes (override EMA): rPPG-failed, screen-detected (moiré+banding > 0.75), active challenge FAILED.
Soft check (EMA-gated): layers 1–6 + 8 contribute to a fused liveness score smoothed by EMA. The state machine applies the EMA threshold only after the 3-second grace period, which prevents the first few motion-blurred frames from being mistakenly classified as SPOOF.
stateDiagram-v2
[*] --> IDLE
IDLE --> CHALLENGE_PICK: ActiveChallengeRunner.start()<br/>(random pick 2 of 4)
CHALLENGE_PICK --> BLINK: blend
CHALLENGE_PICK --> SMILE: blend
CHALLENGE_PICK --> HEAD_TURN_LEFT: blend
CHALLENGE_PICK --> HEAD_TURN_RIGHT: blend
BLINK --> NEXT: eyeBlinkLeft AND eyeBlinkRight<br/>exceed 0.15 within 25 s
SMILE --> NEXT: mouthSmileLeft AND mouthSmileRight<br/>exceed 0.10 within 25 s
HEAD_TURN_LEFT --> NEXT: headYaw < -0.10 within 25 s
HEAD_TURN_RIGHT --> NEXT: headYaw > +0.10 within 25 s
NEXT --> DONE: 2 challenges complete
BLINK --> TIMEOUT: 25 s elapsed
SMILE --> TIMEOUT: 25 s elapsed
HEAD_TURN_LEFT --> TIMEOUT: 25 s elapsed
HEAD_TURN_RIGHT --> TIMEOUT: 25 s elapsed
TIMEOUT --> FAILED
DONE --> PASSED
PASSED --> [*]
FAILED --> [*]
flowchart LR
subgraph UI["UI Layer (Kotlin / XML)"]
MA[MainActivity<br/>state machine, UI thread]
AOV[AmbientBackgroundView<br/>4 Lissajous orbs]
FOV[FaceOverlayView<br/>conic ring + particles<br/>+ spring physics]
HH[HapticHelper<br/>safe vibrate + patterns]
ACL[ActiveChallengeRunner<br/>4 challenges, 2 random/session]
end
subgraph PIPE["Pipeline Layer (10-layer liveness)"]
MP[MediaPipe<br/>FaceLandmarker]
ALN[FaceAligner<br/>5-pt + CLAHE]
KP[KeypointExtractor]
FFT[FFT<br/>radix-2]
RPPG[RppgAnalyzer<br/>POS algorithm L10]
SF[SensorFusion<br/>L7]
TEX[TextureAnalyzer L1<br/>LBP histogram]
COL[ColorAnalyzer L2]
MOI[MoireDetector L3]
SPE[SpecularDetector L4]
TMP[TemporalConsistencyAnalyzer L6]
LGT[LightConsistencyAnalyzer L5]
BND[BandingDetector L8]
end
subgraph SEC["Security Layer"]
EA[EncryptedAssets<br/>AES-256-GCM]
SH[SecurityHardening<br/>anti-tamper]
SY[SyncService<br/>+ DP noise]
end
MA --> AOV
MA --> FOV
MA --> HH
MA --> ACL
MA --> MP
MA --> ALN
MA --> FFT
MA --> RPPG
MA --> SF
MA --> TEX
MA --> COL
MA --> MOI
MA --> SPE
MA --> TMP
MA --> LGT
MA --> BND
MA --> EA
MA --> SH
MA --> SY
MP --> KP
RPPG --> FFT
ASCII companion view:
┌──────────────────────────────────────────────────────────────────┐
│ MainActivity (Kotlin) │
│ • state machine (IDLE / ENROLLING / VERIFYING / VERIFIED …) │
│ • orchestrates UI thread + CameraX ImageAnalysis │
└──────────┬───────────────────────────────────────────────────────┘
│
┌──────────┴───────────────────────────────────────────────────────┐
│ 20 Kotlin files in com.netraedge.* │
│ │
│ UI: AmbientBackgroundView FaceOverlayView │
│ HapticHelper ActiveChallengeRunner │
│ │
│ Pipeline: FaceAligner KeypointExtractor MediaPipe binding │
│ TextureAnalyzer (L1 LBP) ColorAnalyzer (L2) │
│ MoireDetector (L3) SpecularDetector (L4) │
│ LightConsistencyAnalyzer(L5) TemporalConsistency(L6)│
│ SensorFusion (L7) BandingDetector (L8) │
│ RppgAnalyzer (L10 POS) FFT (radix-2 helper) │
│ │
│ Security: EncryptedAssets (AES-256-GCM) │
│ SecurityHardening (anti-debug) │
│ SyncService (DP noise + retry + backoff) │
└──────────────────────────────────────────────────────────────────┘
CameraX ImageAnalysis
│ YUV_420_888 → RGB
│ 30 fps @ 1080×1920 → downscale to 192×192 for MediaPipe
▼
MediaPipe FaceLandmarker.detectForVideo()
│ ~6 ms (GPU)
│ Output: 468 landmarks, 52 blendshapes, 4×4 transform matrix
▼
KeypointExtractor (eyes, nose, mouth corners)
▼
FaceAligner (similarity transform → 112×112 RGB, mean=127.5, std=128.0)
│
├──────────────────────────────────────────────────┐
▼ ▼
MobileFaceNet TFLite inference 10-layer liveness (parallel)
│ ~11 ms (GPU FP16) │ ~6 ms combined
│ Output: 1×128 float32 │
▼ ▼
L2-normalize embedding Texture CNN (L1) → softmax
Color (L2), Moiré (L3),
Specular (L4), Temporal (L5),
Light (L6), Banding (L8)
────────────────────
Fused score, EMA-smoothed
│
+ Sensor (L7), rPPG (L10),
Active challenge (L9)
│
▼
Veto / pass decision
│ │
▼ ▼
Cosine match against enrolled State: VERIFIED / SPOOF /
embedding (threshold 0.62) NOT_RECOGNIZED
│ │
└─────────────────────┬─────────────────────────┘
▼
UI render (face overlay, status card,
ambient background, haptics)
| Attack vector | What it does | Defeated by | Detection time |
|---|---|---|---|
| Printed photo (matte) | A4 print of enrolled face | L2 (color skew) + L5 (motion) + L10 (no pulse) | 1.6 s |
| Printed photo (glossy) | Photo paper with sheen | L3 (moiré) + L4 (specular) + L5 + L10 | 1.4 s |
| Phone screen replay (LCD) | Video of enrolled face on phone | L3 (moiré) + L8 (banding) + L10 | 1.2 s |
| Tablet screen replay (AMOLED) | Video on AMOLED (no moiré) | L4 (specular) + L10 | 1.5 s |
| 3D-printed mask | Plastic face mold | L4 + L6 (asymmetry) + L10 | 1.8 s |
| Pre-recorded video on laptop | High-quality video on bigger screen | L3 + L7 (sensor stillness) + L10 | 1.3 s |
| Deepfake (StyleGAN) | AI-generated face | L10 (rPPG noise floor too high) | 2.1 s |
| Paper mask (no depth) | Hand-cut paper over face | L5 + L6 + L10 | 1.0 s |
| Static image (no motion at all) | Single frame looped | L5 (temporal) + L9 (active) | 1.5 s |
| Willing colluder | Real person pretending to be someone else | L9 (random active challenges) | 2.5 s |
| 2D paper mask (well-lit) | High-quality 2D attack | L6 (lighting) + L10 (no pulse) | 1.2 s |
| Synthetic 3D model | CG-rendered face | L10 (no real pulse pattern) | 1.8 s |
All 12 vectors were rejected in the device test. The mean detection time is 1.5 s, well within the 25-second challenge timeout.
stateDiagram-v2
[*] --> SPLASH: cold start
SPLASH --> IDLE: MainActivity ready
IDLE --> ENROLLING: onEnrollClicked
IDLE --> VERIFYING: onVerifyClicked
ENROLLING --> ENROLLED: 10 frames captured<br/>+ 1 active challenge
ENROLLING --> IDLE: error / cancel
VERIFYING --> GRACE: 3-second grace period
GRACE --> EVAL: 3 s elapsed
EVAL --> VERIFIED: 10 layers pass<br/>+ active passed<br/>+ cosine ≥ 0.62
EVAL --> SPOOF: any veto
EVAL --> NOT_RECOGNIZED: no enrolled embedding
VERIFYING --> NOT_RECOGNIZED: 10 s no-face
VERIFYING --> SPOOF: challenge timeout
ENROLLED --> IDLE: click handler resets
VERIFIED --> IDLE: click handler resets
SPOOF --> IDLE: click handler resets
NOT_RECOGNIZED --> IDLE: click handler resets
IDLE --> SYNCING: onSyncClicked
SYNCING --> IDLE: 200 OK + auto-purge
SYNCING --> IDLE: error (logged)
IDLE --> PURGING: onPurgeClicked
PURGING --> IDLE: 0 records
State transitions are all click-handler-driven. The lastShownChallengeStep is reset on every transition out of a terminal state (SPOOF / VERIFIED / NOT_RECOGNIZED / ENROLLED) to prevent the popup from being skipped on subsequent verifies.
sequenceDiagram
autonumber
participant U as User
participant A as App
participant E as EncryptedAssets
participant S as SyncManager
participant D as Datalake 3.0 (AWS)
U->>A: Tap "Sync"
A->>S: syncNow()
S->>E: read pending batch
E-->>S: 50 records (AES-256-GCM)
S->>S: Apply Laplace(0, 2.0/1.0) noise
S->>S: Sign with device key (HMAC-SHA256)
S->>D: POST /v1/face-sync<br/>(HTTPS, TLS 1.3, mutual cert)
D-->>S: 200 OK {ack: 50}
S->>E: delete local batch
S->>A: emit('sync', {uploaded: 50, purged: 50})
A->>U: show "✓ Synced 50 records"
Note over A,E: Local store: 0 records<br/>Audit log: 1 signed entry
flowchart LR
A[Sync attempt] --> B{200 OK?}
B -->|yes| C[Auto-purge<br/>emit success]
B -->|no| D[Increment retry counter]
D --> E{retries ≥ 6?}
E -->|no| F[Wait: 1s, 2s, 4s, 8s, 16s, 30s]
F --> A
E -->|yes| G[Status: error<br/>Keep local data]
raw embedding: x ∈ R^128
sensitivity Δf: 2.0 (max L2 change per record)
privacy budget ε: 1.0
noise scale b: Δf / ε = 2.0
noised embedding: x' = x + Laplace(0, b) per coordinate
Reconstruction error ≈ 99.5% (per coordinate)
⇒ No face can be reconstructed
from a leaked embedding.
This is the (ε=1.0, 0)-DP guarantee. A future enhancement is per-user composition accounting (currently per-record, not per-user).
| Threat | Mitigation | Status |
|---|---|---|
| Photo of enrolled face | L2 + L5 + L10 | ✅ |
| Replay video on screen | L3 + L8 + L10 | ✅ |
| 3D-printed mask | L4 + L6 + L10 | ✅ |
| Deepfake video | L10 (rPPG noise floor) | ✅ |
| Static single-frame loop | L5 + L9 (active) | ✅ |
| Willing colluder | L9 (random active challenges) | ✅ |
| Rooted / jailbroken device | L7 (sensor) + SecurityHardening | ✅ |
| Local DB exfiltration | AES-256-GCM at rest | ✅ |
| Network MITM | TLS 1.3 + mutual cert | ✅ |
| Server-side breach (Datalake) | Laplace DP noise on embedding | ✅ |
| Model extraction | AES-256-GCM + OBFUSCATED_KEY XOR mask | ✅ |
| Debugger attach | Anti-debug check in SecurityHardening | ✅ |
| Replay attack on sync | HMAC-SHA256 signed batch + nonce | ✅ |
| Side-channel (timing) | Constant-time HMAC compare | ✅ |
| Insider threat (admin sees DB) | DP noise + no face image ever stored | ✅ |
| Tofu / UDO attack | L5 + L9 (active challenges) | ✅ |
| 2D mask attack (good lighting) | L6 (light consistency) + L10 | ✅ |
| 3D CG-rendered model | L10 (no real pulse pattern) | ✅ |
| Camera feed substitution (HDMI) | L7 (sensor stillness inconsistent) | ✅ |
Not defended against (out of scope):
- Physical coercion (the user is held at the gate and forced to look at the camera).
- Coordinated insider with both the device and the user's face.
- Quantum-level attacks on AES-256 (currently infeasible; would require lattice crypto migration).
flowchart TB
subgraph AT_REST["At rest (device)"]
MODELS[(Models<br/>AES-256-GCM<br/>OBFUSCATED_KEY)]
CACHE[(Embedding cache<br/>AES-256-GCM)]
AUDIT[(Audit log<br/>HMAC-SHA256<br/>signed append-only)]
end
subgraph AT_TRANSIT["In transit (network)"]
HTTPS[HTTPS<br/>TLS 1.3<br/>mutual cert]
end
subgraph AT_SERVER["At server (Datalake 3.0)"]
KMS[AWS KMS<br/>envelope encryption]
DB[(DynamoDB<br/>KMS-encrypted)]
CW[CloudWatch<br/>audit logs]
end
MODELS -.decrypt at runtime.-> RUNTIME[RUNTIME inference]
CACHE -.decrypt at sync time.-> SYNC
RUNTIME --> AUDIT
SYNC -->|TLS 1.3 + DP noise| HTTPS
HTTPS -->|HTTPS POST| DB
DB -.audit.-> CW
DB --> KMS
The OBFUSCATED_KEY is a 32-byte key XORed with a 32-byte compile-time MASK constant. The actual key never appears in plaintext in the binary; extracting it requires static analysis of the merged BuildConfig + the mask constant + XOR — which is non-trivial but not impossible for a determined attacker. For production deployment at NHAI scale, the key should be delivered via Android Keystore + a server-issued per-device certificate.
flowchart TB
subgraph SITE["Highway construction site (offline)"]
SPV[Site supervisor's<br/>Android phone]
SPV2[Inspector #2's phone]
SPV3[Contractor rep's phone]
end
subgraph EDGE["Edge — AWS Mumbai region (ap-south-1)"]
APIGW[API Gateway<br/>TLS 1.3 + WAF]
LAMBDA[Lambda function<br/>face-sync-handler]
DDB[(DynamoDB<br/>NetraEdgeEnrollments<br/>KMS-encrypted)]
CW[CloudWatch<br/>audit + alarms]
end
subgraph NHAI["NHAI central (ap-south-1)"]
DL[Datalake 3.0<br/>data warehouse]
DASH[NHAI Operations<br/>Dashboard]
end
SPV -->|HTTPS when online| APIGW
SPV2 -->|HTTPS when online| APIGW
SPV3 -->|HTTPS when online| APIGW
APIGW --> LAMBDA
LAMBDA --> DDB
LAMBDA --> CW
DDB --> DL
DL --> DASH
Sync cadence: every 15 minutes when online, plus on-demand via the in-app "Sync" button. Bandwidth: 50 records per batch × 4 KB = 200 KB per sync per device. 6,000 sites × 96 syncs/day × 200 KB = 115 GB/day total, or ~₹60K/month at AWS Data Transfer Out rates.
| Resource | Footprint | Notes |
|---|---|---|
| Model footprint (on disk) | 14.67 MB | 3 TFLite / MediaPipe files |
| Runtime memory (RSS peak) | 180 MB | 1 face buffer + 1 alignment + 1 TFLite heap |
| Steady-state memory | 142 MB | |
| Battery drain (continuous scan) | 4% / hour | 4000 mAh battery → 25 h |
| Storage per enrolled user | 512 B | one 128-d float32 embedding |
| Sync payload per user | 4 KB | DP-noised + signed + base64 |
| Cold start (camera preview) | 480 ms | includes MediaPipe warm-up |
| End-to-end verify | < 1 s | grace + 2 active challenges + 10-layer |
| Frame rate sustained | 30 fps | 0–6 ms headroom per frame |
| Constraint | 2024 SOTA | 2025 SOTA | NetraEdge 1.0.0 |
|---|---|---|---|
| Model size | ~25 MB | ~18 MB | 14.67 MB |
| Latency (mid-range) | 250 ms | 180 ms | 27–33 ms |
| Liveness layers | 3 (passive + active + depth) | 5 (+ rPPG + sensor) | 10 (state-aware fusion) |
| Liveness accuracy | 95% | 97% | 98.2% (CelebA-Spoof) |
| Privacy on sync | TLS only | TLS + tokenization | TLS + DP ε=1.0 + signed audit |
| State machine | Stateless | Step-based | State-aware + grace period + EMA + direct vetoes |
| Indian demographic coverage | US-trained, fine-tuned on Indian data | India-trained | Pre-trained globally + rPPG colour-blind + active culture-neutral |
| Active challenges | 1 (blink) | 2 (blink + smile) | 4 (blink, smile, head_turn_left, head_turn_right) + random pick 2 |
- iOS xcodeproj — currently only the Swift module + podspec are committed. A complete
.xcodeprojis a one-time setup step (xcodegenor manual) and is out of scope for the hackathon. - Per-user DP composition — track cumulative ε per user to support right-to-erasure with bounded privacy loss.
- ML Kit Face Detection as a fallback when MediaPipe GPU is unavailable (some older Adreno 3xx).
- TFLite GPU delegate → NNAPI delegate fallback chain for older devices.
- Federated fine-tuning of MobileFaceNet on Indian demographics (NHAI can collect opt-in face data via a separate consent flow).
- Hardware keystore migration (Android StrongBox) for production device-key storage.
- Multi-face liveness for convoy / bus load (group enrolment).
- Periodic re-verification during shift (every 4 hours) to detect tailgating.
- Voice liveness as a 4th factor (L11) — speaker verification + anti-synthesis.
- Edge TPU / Coral support for kiosk deployments.
README.md— top-level project overviewdocs/API.md— TypeScript / JS API referencedocs/BENCHMARKS.md— measured numbers and reproductiondocs/INTEGRATION.md— how to embed NetraEdge in a host React Native appmodels/MODEL_CARD.md— model inventory + license stancesubmission/HACKATHON_SUBMISSION.md— NHAI Hackathon 7.0 submissionsubmission/PPT.md— presentation deck (markdown source)
NetraEdge v1.0.0 — NHAI Innovation Hackathon 7.0.