refactor: simplify hashed wallet identifier creation by optimizing seed and address handling logic (#2675)
What changed, and why it matters
This commit changes how Cake Wallet creates a unique, privacy-protecting identifier for a wallet. Previously, the identifier was based only on the wallet's secret seed phrase. Now, if no seed is available, it falls back to using the wallet's main public receiving address. The change is described as a simplification/refactor, but it alters the privacy assumptions of the identifier: a public address is less sensitive than a seed, but it is still wallet-specific information. There is no direct evidence this introduces a security vulnerability, but it changes what data feeds into the hash and could affect how wallets are grouped or recognized across backups/restores.
Review whether using the primary public address as a fallback identifier input is acceptable for all wallet types and privacy models. Confirm that wallets previously returning an empty identifier will now be grouped correctly and that no code path relied on the empty-string behavior. Consider adding tests for seedless/watch-only wallet identifier generation.
Security signals we found
Identifier derivation now includes wallet primary address when seed is unavailable
Removal of empty-string fallback for null seed
Privacy boundary change: public address used as a wallet-grouping input
No change to hash algorithm or salt
Commit is labeled as a refactor/optimization, not a security fix
Evidence from the diff
The function createHashedWalletIdentifier in lib/entities/hash_wallet_identifier.dart was refactored. Before, it returned an empty string if wallet.seed was null. Now it uses wallet.seed ?? wallet.walletAddresses.primaryAddress as hashContent, hashes salt.hashContent with SHA-256, and returns the hex digest. This means wallets without a recoverable seed (e.g., hardware-backed, watch-only, or certain restored wallets) now produce a deterministic identifier based on their primary address rather than an empty string. The salt remains the same. The change removes null-handling and several comments but does not modify the hashing algorithm.
Changed components
lib/entities/hash_wallet_identifier.dartWallet grouping/identification logicBackup/restore wallet matchingInspect captured patch +2 / −7
diff --git a/lib/entities/hash_wallet_identifier.dart b/lib/entities/hash_wallet_identifier.dart
index 8e593ec7..175063eb 100644
--- a/lib/entities/hash_wallet_identifier.dart
+++ b/lib/entities/hash_wallet_identifier.dart
@@ -5,17 +5,12 @@ import 'package:cw_core/wallet_base.dart';
import 'package:hashlib/hashlib.dart';
String createHashedWalletIdentifier(WalletBase wallet) {
- if (wallet.seed == null) return '';
+ final hashContent = wallet.seed ?? wallet.walletAddresses.primaryAddress;
final salt = secrets.walletGroupSalt;
- final combined = '$salt.${wallet.seed}';
+ final combined = '$salt.$hashContent';
- // Convert to UTF-8 bytes.
final bytes = utf8.encode(combined);
-
- // Perform SHA-256 hash.
final digest = sha256.convert(bytes);
-
- // Return the hex string representation of the hash.
return digest.toString();
}
Why this scored 38/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.