The Argon2id parameter block said:
- memory: 46 MiB (46080 KiB)
- iterations: 3
- parallelism: 1
But the source constant in RecoveryKeyManager.kt is:
private const val ARGON2_MEMORY_KB = 46 * 1024
46 * 1024 = 47104, not 46080 (a slipped digit). 46080 KiB would be
45 MiB. The iOS-side docstring in CoupleEncryptionManager.swift
already says 46 MiB = 47104 KiB, so this is the Android-side drift.
Replaced the parameter block with the source-of-truth constant names
(ARGON2_MEMORY_KB, ARGON2_ITERATIONS, ARGON2_PARALLELISM) and the
correct KiB value (47104) so the next reader can grep the code.
Other Batch 3 claims verified clean:
- Encryption version table: EncryptionVersion.STRICT=2, acceptInviteCallable
hardcodes 2, throws if any of wrappedCoupleKey/kdfSalt/kdfParams is null.
- Tink AEAD wire formats: enc:v1:base64, sealed:v1:urlsafe-base64-no-padding,
keybox:v1:urlsafe-base64-no-padding, pub:v1:urlsafe-base64-no-padding,
sha256:urlsafe-base64-no-padding (43 chars). All match the source constants.
- AAD: FieldEncryptor uses coupleId; SealedAnswerEncryptor uses
coupleId|questionId|userId; both match.
- ECIES P-256: UserKeyManager uses
HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM;
ReleaseKeyEncryptor contextInfo is coupleId|questionId|senderUserId|recipientUserId.
- All 5 firestore.rules regex helpers match the manual's reference table.
- wrapReleaseKeyCallable reads the recipient public key from
users/{uid}/devices/primary (verified in function source).
- CoupleKeyStore persists Tink keyset handles in EncryptedSharedPreferences
(Keystore-backed) via SecurePreferencesFactory.