Skip to content

tech-debt(android): replace react-native-fast-crypto with quick-crypto scrypt to drop libsecp256k1.so #30591

@andrepimenta

Description

@andrepimenta

Description

react-native-fast-crypto@2.2.0 ships a prebuilt libsecp256k1.so (4 KB-aligned) inside its package's android/jni/libs/<ABI>/ directory. Google Play flagged this .so as non-compliant with Android's 16 KB page-size requirement on the x86_64 ABI. As a workaround, #30590 drops the x86_64 ABI from production AABs entirely, but the same .so still ships for arm64-v8a with 4 KB alignment — which will eventually trigger the same Play warning on arm64, and is already non-compliant for Android 15+ devices running in 16 KB mode.

We only consume scrypt from react-native-fast-crypto:

// app/core/Engine/controllers/identity/user-storage-controller-init.ts
import { scrypt } from 'react-native-fast-crypto';
// ...
nativeScryptCrypto: scrypt,

react-native-quick-crypto@1.x (Nitro Modules rewrite) ships a Node-compatible crypto.scrypt(password, salt, keylen[, options], callback) API that uses OpenSSL underneath, is 16 KB-aligned, and is actively maintained by Margelo. We already depend on react-native-quick-crypto@0.7.15 so upgrading consolidates two crypto deps into one.

Technical Details

Scope of change

  1. Bump react-native-quick-crypto 0.7.15 → 1.x

    • Requires react-native ≥ 0.75 and New Architecture enabled (✅ we already have newArchEnabled=true).
    • Adds react-native-nitro-modules as a peer dep.
    • Re-evaluate the existing yarn patch (.yarn/patches/react-native-quick-crypto-npm-0.7.15-85c4f4892e.patch) against 1.x — rewrite or drop.
  2. Add a fast-crypto-shaped adapter at the single call site (app/core/Engine/controllers/identity/user-storage-controller-init.ts):

    import QuickCrypto from 'react-native-quick-crypto';
    import { Buffer } from '@craftzdog/react-native-buffer';
    
    export const scrypt = (
      passwd: Uint8Array,
      salt: Uint8Array,
      N: number,
      r: number,
      p: number,
      size: number,
    ): Promise<Uint8Array> =>
      new Promise((resolve, reject) =>
        QuickCrypto.scrypt(
          Buffer.from(passwd),
          Buffer.from(salt),
          size,
          { N, r, p, maxmem: 256 * 1024 * 1024 },
          (err, derived) =>
            err ? reject(err) : resolve(new Uint8Array(derived as Buffer)),
        ),
      );

    ⚠️ Watch maxmem: Node's default is 32 MiB, which is too low for profile-sync params (N=2^17, r=8 → ~134 MiB needed). Set explicitly.

  3. Add a known-vector test asserting our adapter produces the same bytes as fast-crypto did. Use RFC 7914 §12 vectors plus our actual profile-sync params (N=2^17, r=8, p=1, dkLen=32).

  4. Remove the react-native-fast-crypto dependency from package.json and its yarn patch (.yarn/patches/react-native-fast-crypto-npm-2.2.0-57b8a8a01a.patch).

  5. Remove the type declaration (app/declarations/index.d.ts line 15: declare module 'react-native-fast-crypto';).

Verification

  • Both libraries implement RFC 7914 scrypt → byte-for-byte identical output for the same (password, salt, N, r, p, dkLen).
  • After the swap, unzip -l app-prod-release.aab | grep libsecp256k1 should return empty across all ABIs.
  • unzip -l app-prod-release.aab | grep libcrypto_bridge (fast-crypto's JNI shim) should also disappear.

Risk

  • Low. scrypt is a pure function with no persisted state; if the adapter is correct, there's no migration concern.
  • The riskiest piece is the react-native-quick-crypto 0.x → 1.x bump itself, not the scrypt swap. Margelo claims API compatibility in their README.

Acceptance Criteria

  • react-native-fast-crypto removed from package.json and .yarn/patches/.
  • react-native-quick-crypto bumped to a 1.x version with scrypt support.
  • Adapter in place at the user-storage-controller-init scrypt call site.
  • Known-vector unit test asserting RFC 7914 §12 outputs are produced.
  • Production AAB contains no libsecp256k1.so and no libcrypto_bridge.so under any ABI.
  • Profile-sync init time tested on a mid-range Android device — no perceptible regression vs. fast-crypto baseline.
  • CHANGELOG entry added (e.g. "Removed react-native-fast-crypto in favor of react-native-quick-crypto scrypt; reduces Android AAB size and improves 16 KB compliance.").

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    INVALID-ISSUE-TEMPLATEIssue's body doesn't match any issue template.release-7.80.0Issue or pull request that will be included in release 7.80.0

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions