celo-org / celo-org/developer-tooling
changeKeystorePassphrase silently drops blspublickey from validator keystores
- Dominant language
- TypeScript
- Stars
- 44
- Forks
- 36
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
`KeystoreBase.changeKeystorePassphrase` destroys any non-standard top-level field in a V3 keystore. Celo validator keystores generated by geth carry a `blspublickey` field, so changing such a keystore's passphrase silently loses it.
## Cause
`packages/sdk/keystores/src/keystore-base.ts` re-encrypts by decrypting the private key and building a **fresh** V3 object. That object only ever contains `version`, `id`, `address` and `crypto`, so everything else in the original file is dropped:
```
in : {address, blspublickey, crypto, id, version}
out: {address, crypto, id, version}
^^^^^^^^^^^^ silently lost
```
There is no error and no warning — the write succeeds and the field is simply gone.
## Reproduce
`GETH_GEN_KEYSTORE1` in `packages/sdk/keystores/src/test-constants.ts` is a real geth-generated fixture containing a `blspublickey`. Persist it, call `changeKeystorePassphrase`, then re-read the raw entry: the field is absent.
## Not a regression
This predates the removal of `ethereumjs-wallet` (#792). That library's `toV3` had exactly the same behaviour, so the migration neither introduced nor worsened it. It was left alone there deliberately to keep that PR strictly behaviour-neutral and easy to review.
## Suggested fix
Preserve unknown top-level fields across re-encryption — spread the parsed original and overwrite only `crypto` (and `id`), rather than constructing the object from scratch. Add a regression test using the `GETH_GEN_KEYSTORE1` fixture asserting `blspublickey` survives a passphrase change.
Worth deciding at the same time whether `importPrivateKey` should be able to *write* such fields, or whether preservation on re-encryption is the whole scope.
## Impact
Limited. `@celo/keystores` has no consumers inside this monorepo — celocli never reads or writes keystore files — so this only affects external npm consumers of the package who manage geth-generated validator keystores.
Contributor guide
Research direction
Start in packages/sdk/keystores/src/keystore-base.ts at changeKeystorePassphrase and inspect how the fresh V3 object is built. Use GETH_GEN_KEYSTORE1 from packages/sdk/keystores/src/test-constants.ts to reproduce the passphrase change, then add a regression test showing that blspublickey remains present after re-encryption.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 78/100