Skip to content

[Polkadot] Present Polkadot import keyring#34209

Merged
cypt4 merged 6 commits intomasterfrom
brave_53161
Mar 4, 2026
Merged

[Polkadot] Present Polkadot import keyring#34209
cypt4 merged 6 commits intomasterfrom
brave_53161

Conversation

@cypt4
Copy link
Collaborator

@cypt4 cypt4 commented Feb 26, 2026

Polkadot import keyring required to store polkadot imported accounts. This PR also moves encoding\decoding methods to polkadot_utils to reuse them.

Resolves

@github-actions
Copy link
Contributor

github-actions bot commented Feb 26, 2026

@cypt4 cypt4 marked this pull request as ready for review February 26, 2026 13:06
@cypt4 cypt4 requested a review from a team as a code owner February 26, 2026 13:06
@github-actions
Copy link
Contributor

Chromium major version is behind target branch (145.0.7632.109 vs 146.0.7680.32). Please rebase.

@github-actions github-actions bot added the chromium-version-mismatch The Chromium version on the PR branch does not match the version on the target branch label Feb 26, 2026
@github-actions github-actions bot removed the chromium-version-mismatch The Chromium version on the PR branch does not match the version on the target branch label Mar 2, 2026
@cypt4 cypt4 requested a review from supermassive March 2, 2026 13:27
@cmazakas
Copy link
Collaborator

cmazakas commented Mar 2, 2026

Hmm, I'm wondering: do we need to introduce a new class here or can we just extend/modify the existing PolkadotKeyring?

If all we're doing is just storing something like this:

base::flat_map<uint32_t, HDKeySr25519> secondary_keys_;

it feels like we should be able to reify all this functionality into a single umbrella, no?

The only reason I push back against a new keyring type is that it seems to duplicate a lot of functionality and it increases our testing burden a lot more.

@cypt4
Copy link
Collaborator Author

cypt4 commented Mar 3, 2026

Hmm, I'm wondering: do we need to introduce a new class here or can we just extend/modify the existing PolkadotKeyring?

If all we're doing is just storing something like this:

base::flat_map<uint32_t, HDKeySr25519> secondary_keys_;

it feels like we should be able to reify all this functionality into a single umbrella, no?

The only reason I push back against a new keyring type is that it seems to duplicate a lot of functionality and it increases our testing burden a lot more.

I am following bitcoin approach here which is latest coin that supports import.
Actually both polkadot and polkadot_import reuse major part of code and they only bring code related to managing accounts.

@brave-builds
Copy link
Collaborator

Warning

You have got a presubmit warning. Please address it if possible.

Found 8 lines longer than 80 characters (first 5 shown).

Items:

components/brave_wallet/browser/polkadot/polkadot_utils_unittest.cc, line 140, 293 chars
components/brave_wallet/browser/polkadot/polkadot_utils_unittest.cc, line 141, 110 chars
components/brave_wallet/browser/polkadot/polkadot_utils_unittest.cc, line 156, 293 chars
components/brave_wallet/browser/polkadot/polkadot_utils_unittest.cc, line 157, 110 chars
components/brave_wallet/browser/polkadot/polkadot_utils_unittest.cc, line 193, 293 chars

cypt4 added 6 commits March 4, 2026 15:48
Polkadot import keyring required to store polkadot imported accounts.
This PR also moves encoding\decoding methods to polkadot_utils to reuse them.
@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

[puLL-Merge] - brave/brave-core@34209

Description

This PR introduces a new PolkadotImportKeyring class that supports importing Polkadot sr25519 private keys (as opposed to HD-derived keys), along with two new keyring IDs (kPolkadotImport and kPolkadotImportTestnet). It also refactors the existing private key encode/decode logic out of PolkadotKeyring into standalone utility functions in polkadot_utils.cc, making them reusable by both the HD keyring and the new import keyring. Several build dependencies are reorganized (e.g., scrypt_utils and polkadot_utils moved to the :utils source set), and SecureVector is moved from hd_key.h to brave_wallet_types.h for broader accessibility.

Possible Issues

  1. max_memory_bytes discrepancy: In DecodePrivateKeyFromExport (polkadot_utils.cc), the scrypt max_memory_bytes was changed from 64 MB to 256 MB. However, EncodePrivateKeyForExport still uses 64 MB. This inconsistency could be intentional (to accept imports from wallets with higher-cost parameters), but it also means the decode path now allows significantly more memory consumption, which could be a DoS vector when processing untrusted imports.

  2. Copyright year 2026: The new files (polkadot_import_keyring.cc, .h, _unittest.cc) have copyright year 2026, which appears to be a typo.

  3. SecureVector moved to a common header with new dependency: Moving SecureVector to brave_wallet_types.h adds a #include "crypto/process_bound_string.h" to a widely-included common header, which could increase compile times across the codebase.

  4. pkcs8_key_secure not zero-cleared in EncodePrivateKeyForExport (free function): In polkadot_utils.cc, the free-function EncodePrivateKeyForExport creates a SecureVector pkcs8_key_secure from the input span but doesn't explicitly zero it on error paths (relies on SecureAllocator destructor behavior). The SecureAllocator should handle this, but it's worth verifying.

  5. Removed #include "crypto/process_bound_string.h" from hd_key.h: This header was replaced with brave_wallet_types.h. If any code transitively depended on crypto/process_bound_string.h through hd_key.h, it could break.

Security Hotspots

  1. Increased scrypt max_memory_bytes (64 MB → 256 MB in decode): The decode function in polkadot_utils.cc now allows up to 256 MB of memory for scrypt. An attacker crafting a malicious JSON export with high-cost scrypt parameters could trigger significant memory allocation. While the allowed parameter list is checked, the increase from 64 MB to 256 MB broadens the attack surface for resource exhaustion.

  2. Private key material handling in PolkadotImportKeyring: The flat_map<uint32_t, HDKeySr25519> accounts_ stores private key material in memory. When accounts are removed via RemoveAccount, the key is erased from the map but there's no explicit secure zeroing of the memory before deallocation (relies on HDKeySr25519 destructor behavior).

  3. CHECK_IS_TEST() guards: The SetRandBytesForTesting methods use CHECK_IS_TEST(), but the static EncodePrivateKeyForExport overload accepts optional salt/nonce parameters directly without such a guard — callers must ensure they don't pass test values in production.

Changes

Changes

components/brave_wallet/common/brave_wallet.mojom

  • Added kPolkadotImport = 16 and kPolkadotImportTestnet = 17 to KeyringId enum.

components/brave_wallet/common/brave_wallet_types.h

  • Moved SecureVector type alias here from hd_key.h; added crypto/process_bound_string.h include.

components/brave_wallet/common/common_utils.cc / .h

  • Added IsPolkadotImportKeyring() function.
  • Updated IsPolkadotKeyring() to include import keyrings.
  • Updated GetNetworkForPolkadotKeyring(), GetEnabledKeyrings(), GetSupportedKeyringsForNetwork(), and MakeIndexBasedAccountId() to handle new import keyring IDs.

components/brave_wallet/browser/polkadot/polkadot_import_keyring.cc / .h

  • New class managing imported sr25519 accounts via a flat_map<uint32_t, HDKeySr25519>.
  • Supports AddAccount, RemoveAccount, GetAccountAddress, GetPublicKey, SignMessage, EncodePrivateKeyForExport.

components/brave_wallet/browser/polkadot/polkadot_keyring.cc / .h

  • Refactored: EncodePrivateKeyForExport instance method now delegates to a new static overload that takes an HDKeySr25519&.
  • Removed DecodePrivateKeyFromExport (moved to polkadot_utils).
  • Removed inline constants (moved to polkadot_utils.h).

components/brave_wallet/browser/polkadot/polkadot_utils.cc / .h

  • Added free functions EncodePrivateKeyForExport() and DecodePrivateKeyFromExport().
  • Moved AllowedScryptParams, IsAllowedScryptParams, and address prefix constants here.
  • Decode now uses 256 MB max memory for scrypt.

components/brave_wallet/browser/scrypt_utils.cc / .h

  • Removed hd_key.h dependency; now uses brave_wallet_types.h for SecureVector.

components/brave_wallet/browser/BUILD.gn / internal/BUILD.gn

  • Moved polkadot_utils and scrypt_utils to :utils source set.
  • Added polkadot_import_keyring to :hd_keyring source set.
  • Updated visibility and deps.

Test files

  • New polkadot_import_keyring_unittest.cc with comprehensive tests.
  • Moved encode/decode tests from polkadot_keyring_unittest.cc to polkadot_utils_unittest.cc.
  • Updated common_utils_unittest.cc, network_manager_unittest.cc, value_conversion_utils_unittest.cc for new keyring IDs.
sequenceDiagram
    participant Caller
    participant PolkadotImportKeyring
    participant HDKeySr25519
    participant PolkadotKeyring
    participant polkadot_utils
    participant scrypt_utils

    Note over Caller: Import Account Flow
    Caller->>PolkadotImportKeyring: AddAccount(index, pkcs8_key)
    PolkadotImportKeyring->>HDKeySr25519: CreateFromPkcs8(pkcs8_key)
    HDKeySr25519-->>PolkadotImportKeyring: HDKeySr25519 instance
    PolkadotImportKeyring-->>Caller: true/false

    Note over Caller: Get Address
    Caller->>PolkadotImportKeyring: GetAccountAddress(index)
    PolkadotImportKeyring->>HDKeySr25519: GetPublicKey()
    PolkadotImportKeyring->>polkadot_utils: Ss58Address::Encode()
    polkadot_utils-->>Caller: SS58 address string

    Note over Caller: Export Private Key
    Caller->>PolkadotImportKeyring: EncodePrivateKeyForExport(index, password)
    PolkadotImportKeyring->>PolkadotKeyring: EncodePrivateKeyForExport(keypair, password, salt, nonce)
    PolkadotKeyring->>polkadot_utils: EncodePrivateKeyForExport(pkcs8, addr, pw, salt, nonce)
    polkadot_utils->>scrypt_utils: ScryptDeriveKey(password, salt, params)
    scrypt_utils-->>polkadot_utils: derived_key
    polkadot_utils->>scrypt_utils: XSalsaPolyEncrypt(pkcs8, key, nonce)
    scrypt_utils-->>polkadot_utils: ciphertext
    polkadot_utils-->>Caller: JSON string

    Note over Caller: Import from JSON
    Caller->>polkadot_utils: DecodePrivateKeyFromExport(json, password)
    polkadot_utils->>scrypt_utils: ScryptDeriveKey(password, salt, params)
    scrypt_utils-->>polkadot_utils: derived_key
    polkadot_utils->>scrypt_utils: XSalsaPolyDecrypt(ciphertext, nonce, key)
    scrypt_utils-->>polkadot_utils: pkcs8_key
    polkadot_utils-->>Caller: pkcs8_key array
Loading

@cypt4 cypt4 merged commit 25b0b3e into master Mar 4, 2026
23 checks passed
@cypt4 cypt4 deleted the brave_53161 branch March 4, 2026 11:12
@github-actions github-actions bot added this to the 1.89.x - Nightly milestone Mar 4, 2026
vandana-rajan pushed a commit that referenced this pull request Mar 12, 2026
* [Polkadot] Present Polkadot import keyring
Polkadot import keyring required to store polkadot imported accounts.
This PR also moves encoding\decoding methods to polkadot_utils to reuse them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants