New Lite wallets now encrypt their seed and keys with a salted Argon2id
key instead of the unsalted double-SHA256 of the passphrase, which was
cheap to brute-force from a stolen wallet file.
- A shared derive_wallet_key() replaces double-SHA256 across encrypt,
unlock, remove-encryption and seed recovery. KDF 0 is the old
double-SHA256 (unchanged); KDF 1 is Argon2id (moderate: 3 passes,
256 MiB), using sodiumoxide's existing pwhash -- no new dependency.
- The KDF id, salt and parameters are stored in the wallet. A wallet is
written at version 10 only while it is actually Argon2id-encrypted;
every pre-existing wallet (plaintext or double-SHA256) is read and
written byte-for-byte as version 9.
- New-wallets-only: a freshly created or restored wallet encrypts with
Argon2id; a wallet read from disk never changes its KDF, and removing
encryption never changes it. Set DRAGONX_LITE_KDF=legacy to keep new
wallets on double-SHA256.
- An older build (or SilentDragonXLite) opening a version-10 wallet
fails cleanly with "don't know how to read wallet version 10" before
parsing anything, never a silent misread; the seed phrase stays the
cross-wallet recovery path.
Compatibility break (by design, opt-in): a wallet newly encrypted with
Argon2id cannot be opened by older ObsidianDragon or SilentDragonXLite.
Tests: the existing encryption tests now exercise the Argon2id path,
plus the version-10 header, legacy byte-identity and derive_wallet_key
parameter bounds. Validated by the lite oracle suite and the old-vs-new
serialization differential (legacy wallets byte-identical; version-10
round-trips).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>