-
-
Notifications
You must be signed in to change notification settings - Fork 17
feat: use @metamask/native utils #223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Nodonisko
wants to merge
1
commit into
MetaMask:main
Choose a base branch
from
Nodonisko:feat/use-native-utils
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 tasks
sethkfman
pushed a commit
to MetaMask/metamask-mobile
that referenced
this pull request
Dec 5, 2025
## **Description** This PR implements new `@metamask/native-utils` package for C++ cryptography instead of JS implementation. That provides significant performance improvements all across the app. Most visible improvements are during app startup and SRP imports, but for example `keccak256` helps also in many other places. This PR should also have really nice synergy with MetaMask/core#6654 that could shave of another tens of percent for login times. For now I am patching `@metamask/key-tree`, once MetaMask/key-tree#223 is done, patch could be removed, but it may take a while. ### Performance Optimization Results Device: Pixel 4a 5G Tested on SRP with 200+ accounts. | Metric | Before Optimization* | After Optimization | Improvement | % Faster | | :--- | :--- | :--- | :--- | :--- | | **App Loaded to Login screen** | 7s 333ms | **4s 750ms** | ⚡️ 2.58s faster | **35.2%** | | **Dashboard Loaded** | 14s 0ms | **6s 333ms** | ⚡️ 7.67s faster | **54.8%** | | **App is Responsive (60 FPS)** | 18s 783ms | **12s 166ms** | ⚡️ 6.62s faster | **35.2%** | | **SRP Import (Discovery)** | 276s 616ms | **203s 450ms** | ⚡️ 73.17s faster | **26.5%** | _* Before optimalization version has `@metamask/native-utils` completely removed (including secp256k1 that was merged before)._ There should be around 200 - 300ms improvement in account creation time but I am not including this in result because I did many measurements but spread was too big to conclude any results from it. Another big improvement for acccount creation should be MetaMask/core#6654 ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** 1. All accounts are discovered 2. Balances for tokens and total balance is correct 3. Correct receive addresses are generated ## **Screenshots/Recordings** ### Startup + Login https://github.com/user-attachments/assets/24c8ca90-5475-4fa8-9062-30f6fa5133b2 ### SRP Import Observe also FPS counter, as you can see optimized version is maintaining higher FPS (around ~20) compared to non-optimized (around ~10). That should be enough to make app usable even on very slow device during running accounts discovery. To improve FPS even more we need to optimize rerenders and some selectors. In order to reduce discovery total time even more it would require different strategies of discovery, for example instead doing account detail requests one by one, until you find empty one, you could for example request them in batches of 3 which should improve total time significantly. https://github.com/user-attachments/assets/9f6c9825-5d97-415e-903c-8f4327273a2d ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces JS crypto with native implementations via @metamask/native-utils, adds runtime perf shims, patches dependencies, updates iOS pods/Jest config, and optimizes account sorting. > > - **Performance/crypto integration** > - Add `shimPerf.js` to monkey‑patch `@noble/*` and `js-sha3` with native `getPublicKey`, `hmacSha512`, and `keccak256` from `@metamask/native-utils`. > - Update `shim.js` to load the new perf shim. > - **Library patches** > - Patch `@ethereumjs/util` to export `pubToAddress` from `@metamask/native-utils`. > - Patch `@metamask/key-tree` Ed25519 to use `nativeUtils.getPublicKeyEd25519`. > - **Encryption** > - Replace `Buffer.from(..., 'utf-8')` with `TextEncoder().encode(...)` in `quick-crypto.ts` for key derivation and encryption inputs. > - **Selectors** > - Optimize `selectInternalAccounts` sorting by precomputing address indices to avoid repeated `toFormattedAddress` calls. > - **Testing** > - Add Jest mock `app/__mocks__/@metamask/native-utils.js` and map it in `jest.config.js`; expand `transformIgnorePatterns` for native modules. > - **iOS/Pods** > - Bump `NativeUtils` pod to `0.8.0`. > - **Dependencies** > - Upgrade `@metamask/native-utils` to `^0.8.0`; add `js-sha3@0.9.3`, `@noble/hashes@1.8.0`. > - Add Yarn patches/resolutions for `@ethereumjs/util@9.1.0` and `@metamask/key-tree@10.1.1`; update `yarn.lock`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 7ff47ad. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
14 tasks
github-merge-queue bot
pushed a commit
to MetaMask/metamask-mobile
that referenced
this pull request
Dec 8, 2025
## **Description** This PR is from an external contributor. Initial review and context [here](#23270) Credit @Nodonisko This PR implements new `@metamask/native-utils` package for C++ cryptography instead of JS implementation. That provides significant performance improvements all across the app. Most visible improvements are during app startup and SRP imports, but for example `keccak256` helps also in many other places. This PR should also have really nice synergy with MetaMask/core#6654 that could shave of another tens of percent for login times. For now I am patching `@metamask/key-tree`, once MetaMask/key-tree#223 is done, patch could be removed, but it may take a while. ### Performance Optimization Results Device: Pixel 4a 5G Tested on SRP with 200+ accounts. | Metric | Before Optimization* | After Optimization | Improvement | % Faster | | :--- | :--- | :--- | :--- | :--- | | **App Loaded to Login screen** | 7s 333ms | **4s 750ms** | ⚡️ 2.58s faster | **35.2%** | | **Dashboard Loaded** | 14s 0ms | **6s 333ms** | ⚡️ 7.67s faster | **54.8%** | | **App is Responsive (60 FPS)** | 18s 783ms | **12s 166ms** | ⚡️ 6.62s faster | **35.2%** | | **SRP Import (Discovery)** | 276s 616ms | **203s 450ms** | ⚡️ 73.17s faster | **26.5%** | _* Before optimalization version has `@metamask/native-utils` completely removed (including secp256k1 that was merged before)._ There should be around 200 - 300ms improvement in account creation time but I am not including this in result because I did many measurements but spread was too big to conclude any results from it. Another big improvement for acccount creation should be MetaMask/core#6654 ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** 1. All accounts are discovered 2. Balances for tokens and total balance is correct 3. Correct receive addresses are generated ## **Screenshots/Recordings** ### Startup + Login https://github.com/user-attachments/assets/24c8ca90-5475-4fa8-9062-30f6fa5133b2 ### SRP Import Observe also FPS counter, as you can see optimized version is maintaining higher FPS (around ~20) compared to non-optimized (around ~10). That should be enough to make app usable even on very slow device during running accounts discovery. To improve FPS even more we need to optimize rerenders and some selectors. In order to reduce discovery total time even more it would require different strategies of discovery, for example instead doing account detail requests one by one, until you find empty one, you could for example request them in batches of 3 which should improve total time significantly. https://github.com/user-attachments/assets/9f6c9825-5d97-415e-903c-8f4327273a2d ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces JS crypto with native implementations via @metamask/native-utils, adds perf shims, patches key libs, and updates tests/config to support it. > > - **Crypto performance**: > - Add `shimPerf` to monkey-patch `@noble` and `js-sha3` (`secp256k1.getPublicKey`, `hmacSha512`, `keccak256`) to use native C++ via `@metamask/native-utils`. > - Update `shim.js` to load `shimPerf`. > - Switch `quick-crypto` string encoding to `TextEncoder` for key derivation/encryption. > - **Library patches**: > - Patch `@ethereumjs/util` to export `pubToAddress` from `@metamask/native-utils`. > - Patch `@metamask/key-tree` `ed25519` to use `native-utils.getPublicKeyEd25519`. > - **Selectors**: > - Optimize `selectInternalAccounts` sorting to pre-compute indices and reduce `toFormattedAddress` calls. > - **Testing/config**: > - Add Jest mock `app/__mocks__/@metamask/native-utils.js` and map in `jest.config.js`; extend `transformIgnorePatterns`. > - **Dependencies/Pods/Lockfiles**: > - Bump `@metamask/native-utils` to `^0.8.0` (iOS `NativeUtils` pod 0.8.0). > - Add `js-sha3@0.9.3`, pin `@noble/hashes@1.8.0`, add Yarn patches/locks for `@ethereumjs/util@9.1.0` and `@metamask/key-tree@10.1.1`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 95728ed. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: Daniel Suchý <suchydan@gmail.com>
abretonc7s
pushed a commit
to MetaMask/metamask-mobile
that referenced
this pull request
Dec 15, 2025
## **Description** This PR is from an external contributor. Initial review and context [here](#23270) Credit @Nodonisko This PR implements new `@metamask/native-utils` package for C++ cryptography instead of JS implementation. That provides significant performance improvements all across the app. Most visible improvements are during app startup and SRP imports, but for example `keccak256` helps also in many other places. This PR should also have really nice synergy with MetaMask/core#6654 that could shave of another tens of percent for login times. For now I am patching `@metamask/key-tree`, once MetaMask/key-tree#223 is done, patch could be removed, but it may take a while. ### Performance Optimization Results Device: Pixel 4a 5G Tested on SRP with 200+ accounts. | Metric | Before Optimization* | After Optimization | Improvement | % Faster | | :--- | :--- | :--- | :--- | :--- | | **App Loaded to Login screen** | 7s 333ms | **4s 750ms** | ⚡️ 2.58s faster | **35.2%** | | **Dashboard Loaded** | 14s 0ms | **6s 333ms** | ⚡️ 7.67s faster | **54.8%** | | **App is Responsive (60 FPS)** | 18s 783ms | **12s 166ms** | ⚡️ 6.62s faster | **35.2%** | | **SRP Import (Discovery)** | 276s 616ms | **203s 450ms** | ⚡️ 73.17s faster | **26.5%** | _* Before optimalization version has `@metamask/native-utils` completely removed (including secp256k1 that was merged before)._ There should be around 200 - 300ms improvement in account creation time but I am not including this in result because I did many measurements but spread was too big to conclude any results from it. Another big improvement for acccount creation should be MetaMask/core#6654 ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** 1. All accounts are discovered 2. Balances for tokens and total balance is correct 3. Correct receive addresses are generated ## **Screenshots/Recordings** ### Startup + Login https://github.com/user-attachments/assets/24c8ca90-5475-4fa8-9062-30f6fa5133b2 ### SRP Import Observe also FPS counter, as you can see optimized version is maintaining higher FPS (around ~20) compared to non-optimized (around ~10). That should be enough to make app usable even on very slow device during running accounts discovery. To improve FPS even more we need to optimize rerenders and some selectors. In order to reduce discovery total time even more it would require different strategies of discovery, for example instead doing account detail requests one by one, until you find empty one, you could for example request them in batches of 3 which should improve total time significantly. https://github.com/user-attachments/assets/9f6c9825-5d97-415e-903c-8f4327273a2d ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Replaces JS crypto with native implementations via @metamask/native-utils, adds perf shims, patches key libs, and updates tests/config to support it. > > - **Crypto performance**: > - Add `shimPerf` to monkey-patch `@noble` and `js-sha3` (`secp256k1.getPublicKey`, `hmacSha512`, `keccak256`) to use native C++ via `@metamask/native-utils`. > - Update `shim.js` to load `shimPerf`. > - Switch `quick-crypto` string encoding to `TextEncoder` for key derivation/encryption. > - **Library patches**: > - Patch `@ethereumjs/util` to export `pubToAddress` from `@metamask/native-utils`. > - Patch `@metamask/key-tree` `ed25519` to use `native-utils.getPublicKeyEd25519`. > - **Selectors**: > - Optimize `selectInternalAccounts` sorting to pre-compute indices and reduce `toFormattedAddress` calls. > - **Testing/config**: > - Add Jest mock `app/__mocks__/@metamask/native-utils.js` and map in `jest.config.js`; extend `transformIgnorePatterns`. > - **Dependencies/Pods/Lockfiles**: > - Bump `@metamask/native-utils` to `^0.8.0` (iOS `NativeUtils` pod 0.8.0). > - Add `js-sha3@0.9.3`, pin `@noble/hashes@1.8.0`, add Yarn patches/locks for `@ethereumjs/util@9.1.0` and `@metamask/key-tree@10.1.1`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 95728ed. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: Daniel Suchý <suchydan@gmail.com>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR adds support for using faster native functions in mobile app environments for cryptographic functions. It's relying on RN Metro bundler internal mechanism where it automatically prefer files with
.native.tssuffix.Note
Introduces React Native native cryptography implementations and a unified getPublicKeyForCurve API, refactoring key/address derivation to use it and updating exports, tests, coverage, and peer deps.
src/cryptography/cryptography.native.tswith nativehmacSha512,keccak256,pbkdf2Sha512,sha256,ripemd160, andgetPublicKeyForCurveusing@metamask/native-utils/react-native-quick-crypto.getPublicKeyForCurveinsrc/cryptography/cryptography.tsand export viasrc/cryptography/index.tsand rootsrc/index.ts.src/cryptography/cryptography.types.tswith typed override surface.getPublicKeyForCurveinSLIP10Node,derivers/bip39.ts,derivers/cip3.ts, andderivers/bip32.ts.publicKeyToEthAddresssignature to accept optionalCryptographicFunctions; propagate inSLIP10Node.address.getFingerprintto accept optionalCryptographicFunctionsand wire inSLIP10Node.fingerprint.getPublicKeyForCurve; update index export coverage tests.*.native.tsfrom coverage collection.@metamask/native-utils,react-native-quick-cryptowith optional peer metadata.Written by Cursor Bugbot for commit 430bb77. This will update automatically on new commits. Configure here.