Tutorial · 28 min read

H33 Mobile SDK:
iOS and Android Integration Guide

Ship post-quantum biometric authentication in your native mobile apps. This guide covers SDK installation, biometric enrollment, verification flows, offline handling, and enterprise deployment patterns for both iOS (Swift) and Android (Kotlin) — from first line of code to production release.

~50µs
Per Auth
1.2M
Auth/sec
iOS + Android
Native SDKs
PQ
Secure

Why Mobile Biometric Auth Needs a New Foundation

Mobile authentication is converging on biometrics. Apple's Face ID, Android's BiometricPrompt, and third-party face and fingerprint SDKs have trained over three billion users to expect seamless, passwordless authentication. But the security model behind nearly every mobile biometric implementation shares the same structural weakness: biometric templates are stored or compared in plaintext somewhere in the pipeline.

Even when templates are encrypted at rest, the comparison step — the moment the server decides "does this face match that enrollment?" — requires decryption. That decrypted moment is the attack surface. It is vulnerable to memory scraping, side-channel extraction, and, increasingly, quantum-accelerated cryptanalysis. If an adversary records the encrypted template today and gains access to a sufficiently powerful quantum computer within the next decade, they can retroactively decrypt and forge every biometric credential in the database. This is the harvest-now-decrypt-later threat, and mobile devices — with their long-lived credentials and billions of enrolled users — are the primary target.

H33 eliminates this attack surface entirely. The H33 Mobile SDK captures biometric embeddings on-device, transmits them to H33's fully homomorphic encryption (FHE) pipeline, and the matching computation happens entirely on encrypted data. The server never sees a plaintext template — not during enrollment, not during verification, not ever. The result is an authentication system that achieves ~50 microseconds per auth, scales to 1.2 million authentications per second on production hardware, and is secured by post-quantum cryptography from day one.

This guide walks through every step: SDK installation, platform permissions, initialization, enrollment, verification, error handling, offline resilience, and enterprise deployment. All code examples are production-ready Swift (iOS) and Kotlin (Android).

What You Will Build

A native mobile application with FHE-encrypted biometric authentication: face enrollment, face verification, session management, and graceful degradation — all backed by H33's post-quantum pipeline. The same patterns apply to fingerprint, iris, and voice modalities.

Architecture Overview

Before writing code, it helps to understand the data flow. The H33 Mobile SDK is a thin orchestration layer. It does not contain cryptographic primitives — those live server-side in H33's Rust core. The SDK's job is to capture biometric data, extract embeddings via on-device ML models, and transmit those embeddings securely to H33's API.

Step Location What Happens Sensitive Data Exposed?
1. Capture Device Camera captures face/fingerprint/iris image Raw biometric on device only
2. Liveness Device On-device liveness detection rejects spoofing attacks On device only
3. Embedding Device ML model extracts a 128-512 dimension float vector On device only
4. Transmission TLS 1.3 Embedding sent to H33 API over Kyber-secured TLS Encrypted in transit
5. FHE Encrypt H33 Server BFV encryption turns float vector into lattice ciphertext Plaintext exists for <1ms, then zeroed
6. Match H33 Server Cosine similarity computed homomorphically on ciphertext Never decrypted
7. Attest H33 Server ZK proof + Dilithium signature attest to match result Post-quantum attestation
8. Response TLS 1.3 Match/no-match + attestation returned to device No biometric data in response
Key Architecture Principle

The raw biometric image never leaves the device. Only the extracted embedding vector is transmitted. On the server, that embedding is encrypted immediately upon receipt and all subsequent computation occurs on ciphertext. There is no "decryption for comparison" step. This is the fundamental difference between H33 and legacy biometric systems.

Step 1: SDK Installation

The H33 Mobile SDK is distributed as a native framework for each platform. Choose your preferred dependency manager. The SDK has a minimal footprint — ~2.4 MB on iOS, ~1.8 MB on Android — with zero transitive dependencies beyond platform TLS.

iOS — Swift Package Manager

Swift Package.swift
// In Xcode: File → Add Package Dependencies
// URL: https://github.com/h33-ai/h33-ios-sdk

dependencies: [
    .package(
        url: "https://github.com/h33-ai/h33-ios-sdk",
        from: "2.0.0"
    )
]

iOS — CocoaPods

Ruby Podfile
platform :ios, '15.0'

target 'MyApp' do
  use_frameworks!
  pod 'H33SDK', '~> 2.0'
end

Android — Gradle (Kotlin DSL)

Kotlin build.gradle.kts
// Add H33 Maven repository
repositories {
    maven { url = uri("https://maven.h33.ai/releases") }
}

dependencies {
    implementation("ai.h33:h33-android-sdk:2.0.0")
    implementation("ai.h33:h33-biometric:2.0.0")  // Biometric capture module
}

iOS Requirements

  • iOS 15.0+
  • Swift 5.9+
  • Xcode 15.0+
  • Devices with TrueDepth camera (Face ID) or Touch ID

Android Requirements

  • Android API 28+ (Android 9 Pie)
  • Kotlin 1.9+
  • CameraX 1.3+
  • BiometricPrompt API (AndroidX)

Step 2: Platform Permissions

Biometric authentication requires explicit permission grants on both platforms. The permission model differs significantly between iOS and Android, and getting it wrong causes silent failures that are difficult to diagnose in production. Configure permissions before initializing the SDK.

iOS — Info.plist

XML Info.plist
<!-- Camera access for face capture -->
<key>NSCameraUsageDescription</key>
<string>H33 uses your camera for secure biometric enrollment and verification.
Your face data never leaves the device as a raw image.</string>

<!-- Face ID usage -->
<key>NSFaceIDUsageDescription</key>
<string>H33 uses Face ID to confirm your identity before
accessing protected features.</string>

Android — AndroidManifest.xml

XML AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.INTERNET" />

<!-- Require biometric hardware -->
<uses-feature
    android:name="android.hardware.camera"
    android:required="true" />
<uses-feature
    android:name="android.hardware.biometrics.face"
    android:required="false" />
<uses-feature
    android:name="android.hardware.fingerprint"
    android:required="false" />
Android Runtime Permissions

The CAMERA permission on Android requires a runtime request starting with API 23. The H33 SDK provides a H33PermissionHelper utility that handles the request lifecycle, but you must call it before invoking any capture method. Failing to do so throws H33PermissionDeniedException.

Step 3: SDK Initialization

Initialize the H33 client once at application launch. The client maintains an internal connection pool, handles token refresh, and manages retry logic. Creating multiple client instances is wasteful and unsupported — the SDK enforces a singleton pattern.

iOS Initialization

Swift AppDelegate.swift
import H33SDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {

        // Initialize H33 with your API key
        let config = H33Config(
            apiKey: "h33_pk_your_api_key_here",
            environment: .production,
            region: .usEast1
        )

        // Optional: configure biometric capture settings
        config.biometric.captureMode = .faceOnly
        config.biometric.livenessCheck = .active         // Require active liveness
        config.biometric.minConfidence = 0.85            // Embedding quality gate
        config.biometric.maxRetries = 3

        // Network settings
        config.network.timeout = 10                      // seconds
        config.network.retryPolicy = .exponentialBackoff
        config.network.certificatePinning = true

        H33.initialize(with: config)

        return true
    }
}

Android Initialization

Kotlin MainApplication.kt
import ai.h33.sdk.H33
import ai.h33.sdk.H33Config
import ai.h33.sdk.BiometricMode
import ai.h33.sdk.LivenessLevel

class MainApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        val config = H33Config.builder()
            .apiKey("h33_pk_your_api_key_here")
            .environment(H33Config.Environment.PRODUCTION)
            .region(H33Config.Region.US_EAST_1)
            // Biometric capture settings
            .biometricMode(BiometricMode.FACE_ONLY)
            .livenessLevel(LivenessLevel.ACTIVE)
            .minConfidence(0.85f)
            .maxRetries(3)
            // Network settings
            .timeout(10_000L)                            // milliseconds
            .certificatePinning(true)
            .build()

        H33.initialize(this, config)
    }
}
API Key Security

Never hardcode your API key in source files. On iOS, store it in the Keychain or use a .xcconfig file excluded from version control. On Android, use the BuildConfig mechanism with a local.properties entry or Android Keystore. The H33 SDK accepts keys from SecureStorage on both platforms — see the API documentation for the recommended pattern.

Step 4: Biometric Enrollment

Enrollment is the one-time process of creating an encrypted biometric template for a user. The SDK captures a face (or fingerprint, iris, or voice sample), runs on-device liveness detection, extracts an embedding vector, and transmits it to H33 for FHE encryption and storage. The enrolled template exists only as a lattice-based ciphertext — it cannot be reversed to reconstruct the original biometric.

iOS Enrollment Flow

Swift EnrollmentViewController.swift
import H33SDK
import UIKit

class EnrollmentViewController: UIViewController {

    private let captureView = H33BiometricCaptureView()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupCaptureView()
    }

    private func setupCaptureView() {
        captureView.delegate = self
        captureView.mode = .enrollment
        captureView.overlay = .faceGuide          // Shows face alignment oval
        view.addSubview(captureView)
        captureView.frame = view.bounds
    }

    func startEnrollment(userId: String) {
        Task {
            do {
                // Step 1: Capture face + run liveness check
                let capture = try await captureView.capture()

                // Step 2: Verify liveness passed
                guard capture.livenessResult == .live else {
                    showError("Liveness check failed. Please try again.")
                    return
                }

                // Step 3: Enroll with H33
                let enrollment = try await H33.biometric.enroll(
                    userId: userId,
                    embedding: capture.embedding,     // Float vector from on-device ML
                    modality: .face,
                    metadata: EnrollmentMetadata(
                        deviceModel: UIDevice.current.model,
                        osVersion: UIDevice.current.systemVersion,
                        captureQuality: capture.qualityScore
                    )
                )

                // Step 4: Store enrollment reference locally
                try H33SecureStorage.save(
                    key: "h33_enrollment_\(userId)",
                    value: enrollment.enrollmentId
                )

                showSuccess("Enrollment complete. Template ID: \(enrollment.enrollmentId)")

            } catch let error as H33Error {
                handleH33Error(error)
            }
        }
    }
}

// MARK: - H33BiometricCaptureDelegate
extension EnrollmentViewController: H33BiometricCaptureDelegate {
    func captureDidDetectFace(_ aligned: Bool) {
        // Update UI: show green border when face is aligned
        captureView.borderColor = aligned ? .systemGreen : .systemRed
    }

    func captureDidFail(error: H33CaptureError) {
        showError(error.localizedDescription)
    }
}

Android Enrollment Flow

Kotlin EnrollmentActivity.kt
import ai.h33.sdk.H33
import ai.h33.sdk.biometric.H33CaptureView
import ai.h33.sdk.biometric.CaptureMode
import ai.h33.sdk.biometric.Modality
import ai.h33.sdk.model.EnrollmentMetadata

class EnrollmentActivity : AppCompatActivity() {

    private lateinit var captureView: H33CaptureView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_enrollment)

        captureView = findViewById(R.id.h33CaptureView)
        captureView.mode = CaptureMode.ENROLLMENT
        captureView.overlay = CaptureMode.FACE_GUIDE
    }

    fun startEnrollment(userId: String) {
        lifecycleScope.launch {
            try {
                // Step 1: Capture face + liveness
                val capture = captureView.capture()

                // Step 2: Verify liveness
                if (!capture.isLive) {
                    showError("Liveness check failed.")
                    return@launch
                }

                // Step 3: Enroll with H33 API
                val enrollment = H33.biometric.enroll(
                    userId = userId,
                    embedding = capture.embedding,
                    modality = Modality.FACE,
                    metadata = EnrollmentMetadata(
                        deviceModel = Build.MODEL,
                        osVersion = Build.VERSION.RELEASE,
                        captureQuality = capture.qualityScore
                    )
                )

                // Step 4: Store enrollment reference in EncryptedSharedPreferences
                H33SecureStorage.save(
                    context = this@EnrollmentActivity,
                    key = "h33_enrollment_$userId",
                    value = enrollment.enrollmentId
                )

                showSuccess("Enrollment complete: ${enrollment.enrollmentId}")

            } catch (e: H33Exception) {
                handleH33Error(e)
            }
        }
    }
}

What Happens Server-Side During Enrollment

When H33.biometric.enroll() is called, the SDK makes a single API call to H33's enrollment endpoint. Server-side, the following pipeline executes in approximately 1.5 milliseconds:

  1. Input validation — Embedding dimension check, NaN/Inf rejection, L2 normalization verification.
  2. BFV encryption — The float vector is quantized and encrypted into a BFV ciphertext. The plaintext is zeroed from memory immediately after encryption.
  3. SIMD packing — Up to 32 user templates are packed into a single ciphertext via SIMD batching, reducing storage to approximately 256KB per user.
  4. Attestation — A Dilithium signature is generated over the enrollment event, creating an auditable post-quantum proof that the enrollment occurred.
  5. Storage — The encrypted template is persisted. The original embedding is permanently erased.
Multi-Sample Enrollment

For highest accuracy in production, capture 3-5 samples during enrollment rather than a single image. The H33 SDK supports multi-sample enrollment via captureView.captureMultiple(count: 5). The server averages the encrypted embeddings to produce a more robust template, reducing false rejection rates by approximately 40% compared to single-sample enrollment.

Step 5: Biometric Verification

Verification is the recurring authentication event. The user presents their face (or fingerprint), the SDK captures and extracts an embedding, and H33 compares it against the enrolled template entirely in the encrypted domain. No decryption occurs during the match. The response includes a match score, a boolean result, and a zero-knowledge proof attesting to the computation's integrity.

iOS Verification

Swift AuthViewController.swift
import H33SDK

class AuthViewController: UIViewController {

    private let captureView = H33BiometricCaptureView()

    func authenticate(userId: String) {
        Task {
            do {
                // Capture + liveness in one call
                let capture = try await captureView.capture()

                guard capture.livenessResult == .live else {
                    showError("Liveness check failed.")
                    return
                }

                // Verify against enrolled template
                let result = try await H33.biometric.verify(
                    userId: userId,
                    embedding: capture.embedding,
                    options: VerifyOptions(
                        threshold: 0.75,            // Cosine similarity threshold
                        requireZkProof: true,       // Include ZK attestation
                        requirePqAttestation: true  // Include Dilithium sig
                    )
                )

                if result.matched {
                    // Authentication succeeded
                    let session = result.session
                    print("Auth latency: \(result.latencyMicroseconds)µs")
                    print("Similarity: \(result.score)")
                    print("ZK proof valid: \(result.zkProofValid)")
                    print("PQ attestation: \(result.pqAttestationValid)")

                    // Navigate to protected content
                    navigateToHome(session: session)
                } else {
                    showError("Biometric verification failed. Score: \(result.score)")
                }

            } catch let error as H33Error {
                handleH33Error(error)
            }
        }
    }
}

Android Verification

Kotlin AuthActivity.kt
import ai.h33.sdk.H33
import ai.h33.sdk.biometric.VerifyOptions

class AuthActivity : AppCompatActivity() {

    private lateinit var captureView: H33CaptureView

    fun authenticate(userId: String) {
        lifecycleScope.launch {
            try {
                val capture = captureView.capture()

                if (!capture.isLive) {
                    showError("Liveness check failed.")
                    return@launch
                }

                val result = H33.biometric.verify(
                    userId = userId,
                    embedding = capture.embedding,
                    options = VerifyOptions(
                        threshold = 0.75f,
                        requireZkProof = true,
                        requirePqAttestation = true
                    )
                )

                if (result.matched) {
                    Log.d("H33", "Auth latency: ${result.latencyMicroseconds}µs")
                    Log.d("H33", "Similarity: ${result.score}")
                    Log.d("H33", "ZK proof: ${result.zkProofValid}")

                    navigateToHome(result.session)
                } else {
                    showError("Verification failed. Score: ${result.score}")
                }

            } catch (e: H33Exception) {
                handleH33Error(e)
            }
        }
    }
}

Understanding the Verification Response

Field Type Description
matched Bool Whether the cosine similarity exceeds the configured threshold
score Float Cosine similarity score (0.0 to 1.0), computed homomorphically
latencyMicroseconds UInt64 Server-side auth latency (~50µs in production)
zkProofValid Bool Whether the STARK proof verified successfully
pqAttestationValid Bool Whether the Dilithium signature on the result is valid
session H33Session Authenticated session object with token and expiry

Step 6: Session Management

After successful verification, the SDK returns an H33Session object containing a signed JWT and a session resume token. The JWT is short-lived (default: 15 minutes). The resume token allows transparent session extension without re-capturing biometrics, as long as the device has not left the user's possession (measured via continuous device attestation).

iOS Session Handling

Swift SessionManager.swift
class SessionManager {

    static let shared = SessionManager()
    private var currentSession: H33Session?

    /// Check if the current session is still valid
    var isAuthenticated: Bool {
        guard let session = currentSession else { return false }
        return !session.isExpired
    }

    /// Store a new session after successful verification
    func setSession(_ session: H33Session) {
        currentSession = session
        // Persist resume token securely
        try? H33SecureStorage.save(
            key: "h33_resume_token",
            value: session.resumeToken
        )
    }

    /// Attempt to resume an expired session without re-capture
    func resumeSession() async throws -> H33Session {
        guard let resumeToken = try? H33SecureStorage.load(
            key: "h33_resume_token"
        ) else {
            throw H33Error.sessionExpired
        }

        let session = try await H33.session.resume(token: resumeToken)
        setSession(session)
        return session
    }

    /// Sign out and invalidate all tokens
    func signOut() async {
        if let session = currentSession {
            try? await H33.session.revoke(session: session)
        }
        currentSession = nil
        try? H33SecureStorage.delete(key: "h33_resume_token")
    }
}

Step 7: Error Handling and Edge Cases

Production mobile applications must handle every failure mode gracefully. The H33 SDK defines a structured error hierarchy that maps directly to actionable recovery paths. Treating all errors as generic failures is the single most common integration mistake — each error type has a distinct correct response.

Error Cause Correct Recovery
H33Error.networkTimeout Server unreachable or slow connection Retry with exponential backoff (SDK handles this)
H33Error.livenessCheckFailed Presentation attack detected (photo/video/mask) Show "Try again" with guidance; log for fraud review
H33Error.lowQualityCapture Poor lighting, blur, or partial face Show capture quality hints; allow retry
H33Error.userNotEnrolled No template exists for this userId Redirect to enrollment flow
H33Error.templateExpired Template exceeded configured TTL Re-enrollment required
H33Error.rateLimited Too many verification attempts Show cooldown timer; do NOT allow brute force
H33Error.attestationFailed ZK proof or Dilithium signature invalid Reject auth; this may indicate server tampering
H33Error.cameraPermissionDenied User denied camera access Show settings deep-link to re-grant permission

Comprehensive Error Handler (iOS)

Swift H33ErrorHandler.swift
func handleH33Error(_ error: H33Error) {
    switch error {

    case .networkTimeout, .networkError:
        // SDK already retried with exponential backoff.
        // Show offline state if all retries exhausted.
        showOfflineState()

    case .livenessCheckFailed(let attempts):
        if attempts >= 3 {
            // Possible spoofing attack — lock out temporarily
            lockAccount(duration: .minutes(5))
            logSecurityEvent(.livenessFailure, attempts: attempts)
        } else {
            showRetryWithGuidance("Ensure good lighting and look directly at the camera.")
        }

    case .lowQualityCapture:
        showRetryWithGuidance("Move to a well-lit area and hold the device steady.")

    case .userNotEnrolled:
        navigateToEnrollment()

    case .rateLimited(let retryAfter):
        showCooldown(seconds: retryAfter)

    case .attestationFailed:
        // Critical security event — do NOT silently continue
        logSecurityEvent(.attestationFailure)
        showCriticalError("Authentication integrity check failed.")

    case .cameraPermissionDenied:
        showSettingsDeepLink(
            message: "Camera access is required for biometric authentication."
        )

    default:
        showGenericError(error.localizedDescription)
    }
}
Critical: Never Ignore Attestation Failures

If zkProofValid or pqAttestationValid returns false, the authentication response may have been tampered with. This is not a transient error — it is a potential security incident. Your application must reject the authentication and log the event for investigation. Do not fall back to a "trust the match score anyway" path.

Offline and Degraded-Network Handling

Mobile applications frequently lose connectivity — elevators, subways, airplane mode, poor cellular coverage. H33's architecture is server-side, which means full FHE verification requires network access. However, the SDK provides two strategies for degraded connectivity:

Strategy 1: Session Resume (Preferred)

If the user was recently authenticated, the locally cached resume token can re-establish the session when connectivity returns. The SDK queues the resume request and executes it as soon as the network is available. For offline intervals under the session TTL (configurable, default 15 minutes), this is transparent to the user.

Strategy 2: Device-Local Biometric Fallback

For applications that must allow access during extended offline periods, the SDK supports a device-local fallback using the platform's native biometric API (Face ID / Touch ID on iOS, BiometricPrompt on Android). This does NOT use H33's FHE pipeline — it relies on the device's Secure Enclave or TEE. Access granted via fallback is flagged in the session metadata so your backend can enforce re-verification when connectivity resumes.

Swift OfflineFallback.swift
func authenticateWithFallback(userId: String) async {
    do {
        // Primary: H33 FHE-encrypted verification
        let result = try await H33.biometric.verify(
            userId: userId,
            embedding: capture.embedding
        )
        handleVerification(result)

    } catch H33Error.networkError {
        // Fallback: device-local biometric check
        let context = LAContext()
        let reason = "Authenticate offline using Face ID"

        do {
            let success = try await context.evaluatePolicy(
                .deviceOwnerAuthenticationWithBiometrics,
                localizedReason: reason
            )
            if success {
                // Grant limited access; flag for re-verification
                grantOfflineAccess(userId: userId)
            }
        } catch {
            showError("Offline authentication failed.")
        }
    }
}
Security Tradeoff

Device-local fallback provides convenience but reduces the security guarantee. The biometric match occurs in the device's Secure Enclave, not in H33's FHE pipeline. There is no ZK proof, no post-quantum attestation, and no server-side rate limiting. Use this only when connectivity loss is expected and the risk profile justifies it. Always enforce re-verification via H33 when the network returns.

H33 API Endpoints Reference

The mobile SDK wraps these REST endpoints. You can also call them directly from your backend for server-to-server flows. All endpoints require an Authorization: Bearer header with your H33 API key.

Method Endpoint Description Latency
POST /v1/biometric/enroll Create encrypted biometric template ~1.5ms
POST /v1/biometric/verify FHE-encrypted match + ZK proof + PQ attestation ~50µs
POST /v1/session/resume Resume session with resume token ~2ms
POST /v1/session/revoke Invalidate active session ~1ms
DELETE /v1/biometric/template/{userId} Delete enrolled template (GDPR right to erasure) ~3ms
GET /v1/biometric/status/{userId} Check enrollment status and template age ~1ms

Direct API Call Example

Shell · curl POST /v1/biometric/verify
curl -X POST https://api.h33.ai/v1/biometric/verify \
  -H "Authorization: Bearer $H33_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "user_abc123",
    "embedding": [0.0234, -0.1893, 0.4521, ...],
    "modality": "face",
    "options": {
      "threshold": 0.75,
      "require_zk_proof": true,
      "require_pq_attestation": true
    }
  }'

// Response
{
  "matched": true,
  "score": 0.9127,
  "latency_us": 48,
  "zk_proof_valid": true,
  "pq_attestation_valid": true,
  "session": {
    "token": "eyJhbG...",
    "expires_at": "2026-02-24T15:30:00Z",
    "resume_token": "rt_9xKm..."
  }
}

Liveness Detection Deep Dive

Liveness detection is the first line of defense against presentation attacks — printed photos, video replays, silicone masks, and deepfake injections. The H33 SDK supports three liveness levels, each trading convenience for security.

Passive Liveness

Analyzes a single captured frame for artifacts: moire patterns, screen reflections, paper edges, inconsistent specular highlights. Zero user interaction. Catches printed photos and basic screen replays.

Use case: Low-risk consumer apps

Detection rate: ~94%

Active Liveness (Recommended)

Prompts the user to perform a random micro-action: blink, turn head slightly, smile. Multi-frame analysis detects temporal inconsistencies that defeat static spoofs and most video replay attacks.

Use case: Financial, healthcare, enterprise

Detection rate: ~99.3%

Depth-Based Liveness

Uses TrueDepth (iOS) or structured-light sensors (select Android devices) to build a 3D depth map. Rejects all 2D presentation attacks and most 3D masks. Requires specific hardware.

Use case: Government ID, high-value transactions

Detection rate: ~99.8%

Injection Attack Detection

The SDK validates that the camera feed originates from the physical camera hardware, not from a virtual camera or hooked video pipeline. Detects Xposed/Frida/Magisk-based injection on Android and jailbreak-based camera spoofing on iOS.

Use case: All production deployments

Always enabled

Swift Liveness Configuration
// Configure liveness level during SDK initialization
config.biometric.livenessCheck = .active       // .passive | .active | .depth
config.biometric.livenessActions = [.blink, .turnLeft, .smile]  // Random subset used
config.biometric.injectionDetection = true     // Always recommended

Multimodal Biometric Fusion

Single-modality biometrics (face alone, fingerprint alone) have well-known failure modes: identical twins defeat face recognition; wet fingers defeat capacitive sensors; voice changes with illness. Multimodal fusion combines two or more modalities, dramatically reducing both false acceptance rates (FAR) and false rejection rates (FRR).

The H33 SDK supports enrolling and verifying with multiple modalities in a single API call. The server performs score-level fusion in the encrypted domain, producing a combined match score that is more robust than any individual modality.

Kotlin MultimodalAuth.kt
// Capture face + voice in sequence
val faceCapture = faceCaptureView.capture()
val voiceCapture = voiceCaptureView.captureVoice(
    phrase = "My voice is my password",
    durationMs = 3000
)

// Verify with both modalities in one call
val result = H33.biometric.verifyMultimodal(
    userId = userId,
    embeddings = mapOf(
        Modality.FACE to faceCapture.embedding,
        Modality.VOICE to voiceCapture.embedding
    ),
    fusionStrategy = FusionStrategy.WEIGHTED_SUM,  // or .MAX, .PRODUCT
    weights = mapOf(
        Modality.FACE to 0.7f,
        Modality.VOICE to 0.3f
    )
)

Log.d("H33", "Fused score: ${result.score}, matched: ${result.matched}")

Privacy and Compliance

Biometric data is the most heavily regulated category of personal information globally. The H33 SDK is designed to help you meet compliance requirements across jurisdictions, but the legal obligation ultimately rests with your organization. Here is how H33's architecture maps to major regulatory frameworks.

Regulation Requirement How H33 Addresses It
GDPR (EU) Biometric data is "special category" — requires explicit consent, purpose limitation, data minimization, right to erasure FHE encryption ensures data minimization (server never sees plaintext). Template deletion via DELETE /v1/biometric/template/{userId}. Consent management is your responsibility.
BIPA (Illinois) Written consent, retention schedule, no sale of biometric data, private right of action H33 never possesses plaintext biometric data. Encrypted templates have configurable TTL. H33 does not sell or share data.
CCPA (California) Right to know, right to delete, right to opt out of sale Full audit trail via Dilithium-attested events. Deletion API. No data sale.
PIPL (China) Separate consent for biometrics, data localization, security assessment for cross-border transfer H33 supports region-specific deployment (China region available). Consent is your responsibility.
Consent Implementation

The H33 SDK includes a ConsentManager utility that records consent timestamps, consent versions, and purpose descriptions. It stores consent records both locally (for offline access) and server-side (for audit). Use H33.consent.record(userId:, purpose:, version:) before calling any enrollment method. This does not replace legal review — it provides the technical mechanism.

Testing Your Integration

The H33 SDK provides a sandbox environment and mock capture utilities for automated testing. Never use real biometric data in CI/CD pipelines.

Sandbox Environment

Swift Test Configuration
// Point to H33 sandbox for integration tests
let config = H33Config(
    apiKey: "h33_sk_test_your_sandbox_key",
    environment: .sandbox,                  // Uses sandbox API, no billing
    region: .usEast1
)

// Use mock capture for unit tests (no camera required)
let mockEmbedding = H33TestUtils.generateMockEmbedding(
    dimensions: 128,
    similarity: 0.92   // Will produce a match at threshold 0.75
)

let result = try await H33.biometric.verify(
    userId: "test_user_001",
    embedding: mockEmbedding
)
XCTAssertTrue(result.matched)

Sandbox Limits

  • 1,000 enrollments
  • 10,000 verifications/month
  • Templates expire after 24 hours
  • No SLA guarantees

Test Utilities

  • H33TestUtils.generateMockEmbedding()
  • H33TestUtils.generateNonMatchEmbedding()
  • H33TestUtils.simulateNetworkFailure()
  • H33TestUtils.simulateLivenessFail()

Production Deployment Checklist

Before shipping to the App Store or Google Play, verify every item on this checklist. Each item addresses a failure mode observed in production mobile biometric deployments.

1. API Key in Secure Storage

Verify the API key is loaded from Keychain (iOS) or EncryptedSharedPreferences (Android), not hardcoded in source.

2. Certificate Pinning Enabled

Confirm certificatePinning = true in SDK config. This prevents MITM attacks on the API connection.

3. Liveness Set to Active or Depth

Passive liveness is insufficient for production. Require .active at minimum.

4. Attestation Verification Enforced

Verify your code rejects auth results where zkProofValid or pqAttestationValid is false.

5. Rate Limiting Respected

Confirm your error handler shows a cooldown when H33Error.rateLimited is received. Do not allow infinite retries.

6. Consent Recorded Before Enrollment

Verify H33.consent.record() is called before every enrollment, with the correct purpose and consent version.

7. Template Deletion Implemented

Confirm your settings screen includes a "Delete my biometric data" option that calls DELETE /v1/biometric/template/{userId}.

8. Offline Fallback Behavior Tested

Test with airplane mode: verify session resume works within TTL and device-local fallback works outside TTL.

9. Multi-Sample Enrollment

Production enrollment should capture 3-5 samples for robust template creation.

10. App Transport Security (iOS)

Verify no ATS exceptions are configured. The H33 API supports TLS 1.3 exclusively.

Performance Characteristics

The H33 Mobile SDK adds minimal overhead to the authentication flow. The dominant latency components are network round-trip time (varies by connection quality) and on-device capture/liveness processing. Server-side auth is ~50 microseconds — negligible compared to network latency.

End-to-End Latency Breakdown (Typical)

On-device capture + liveness~800ms
On-device embedding extraction~120ms
Network round-trip (LTE)~80ms
H33 server-side auth (FHE + ZKP + attestation)~50µs
Total (user-perceived)~1.0s

The ~50 microsecond server-side latency means H33 is never the bottleneck. For detailed server-side benchmarks, see the full auth pipeline benchmark and the January 2026 benchmark report.

React Native and Flutter

For cross-platform applications, H33 provides thin wrapper packages around the native SDKs. These wrappers expose the same API surface with platform-idiomatic bindings.

React Native

npm install @h33/react-native-sdk

Uses the native iOS and Android SDKs under the hood via JSI bridge. Requires react-native >= 0.73.

Flutter

flutter pub add h33_sdk

Platform channel implementation delegates to native SDKs. Supports Dart >= 3.2 and Flutter >= 3.16.

Both wrappers support the full feature set: enrollment, verification, multimodal fusion, session management, and offline fallback. The native capture views are embedded as platform views (not rendered in the cross-platform UI layer) to maintain camera performance.

Enterprise Deployment Patterns

Enterprise mobile deployments introduce additional requirements: MDM integration, multi-tenant isolation, audit logging, and compliance with industry-specific regulations like HIPAA (healthcare), PCI DSS (payments), and SOX (financial reporting).

Multi-Tenant Configuration

Enterprise apps often serve multiple organizations from a single binary. The H33 SDK supports per-tenant isolation via the tenantId parameter. Each tenant has isolated template storage, independent rate limits, and separate audit logs.

Kotlin Multi-Tenant Setup
// Switch tenant context (e.g., after user selects organization)
H33.setTenant("tenant_acme_corp")

// All subsequent SDK calls are scoped to this tenant
val result = H33.biometric.verify(
    userId = "employee_12345",
    embedding = capture.embedding
)

// Tenant isolation is enforced server-side:
// - employee_12345 in tenant_acme_corp cannot match
//   against templates in tenant_other_org
// - Rate limits are per-tenant
// - Audit logs are per-tenant

MDM and App Configuration

For MDM-managed devices, the SDK reads configuration from managed app configuration keys (iOS) and Android Enterprise managed configurations. This allows IT administrators to set the API key, environment, liveness level, and allowed modalities without modifying the application binary.

Audit Logging

Every enrollment and verification event is logged with a Dilithium-signed audit trail. The audit record includes: timestamp, user ID, device fingerprint, liveness result, match result, and attestation hashes. Audit logs are immutable and queryable via the H33 Admin API.


Migrating from Legacy Biometric Systems

If you are migrating from a legacy biometric provider (Auth0, Firebase Auth, AWS Cognito with custom biometric, or a bespoke system), the H33 SDK supports a phased migration strategy:

  1. Dual-enrollment phase — New enrollments go to H33. Existing users continue authenticating against the legacy system.
  2. Progressive re-enrollment — When a legacy user authenticates successfully, silently capture a new embedding and enroll it with H33 in the background.
  3. Cutover — Once re-enrollment reaches your target percentage (typically 95%+), switch primary authentication to H33 and decommission the legacy system.
  4. Template deletion — Delete all plaintext templates from the legacy system. They are now replaced by FHE-encrypted templates in H33.
Migration Safety

During the dual-enrollment phase, the SDK provides a H33.migration.enrollSilently() method that runs enrollment in the background without interrupting the user's authentication flow. This method captures a fresh embedding from the current verification session and enrolls it with H33. The user experiences zero additional friction.

What's Next

This guide covered the core integration path: installation, permissions, initialization, enrollment, verification, session management, error handling, offline fallback, liveness, multimodal fusion, compliance, testing, and enterprise deployment. For deeper dives into specific topics:

The H33 Mobile SDK ships post-quantum biometric authentication to the devices your users carry every day. Three billion smartphones, each one a potential enrollment point for FHE-encrypted, zero-knowledge-attested, quantum-resistant identity. Get started with a free API key and have your first enrollment running in under five minutes.

Ready to Go Quantum-Secure?

Start protecting your users with post-quantum authentication today. 1,000 free auths, no credit card required.

Get Free API Key →

Build With Post-Quantum Security

Enterprise-grade FHE, ZKP, and post-quantum cryptography. One API call. Sub-millisecond latency.

Get Free API Key → Read the Docs
Free tier · 10,000 API calls/month · No credit card required
Verify It Yourself