Repository navigation
feat: derive safe children at BIP44 paths - #9974
Conversation
Safe child keys move from the single-level m/<n>' scheme to
m/44'/<coinType>'/<slot>'/<account>' for the user child and every MPC
child, with multisig co-signers at the soft twin m/44/<coinType>/<slot>/
<account>. coinType comes from statics bip44CoinType and slot from
SAFE_ROOT_SLOT_ORDINALS. Clean cutover, no single-level support left.
sdk-lib-safes:
- strict BIP44 path brands (exactly 4 levels, purpose 44, slot in the
statics ordinals, canonical decimal, < 2^31)
- getSafeBip44CoinType, buildSafeBip44Path, toSoftTwinPath,
parseSafeBip44Path, deriveSafeChildTriplet
- derive functions take a branded path instead of an index
- drop parseSafeDerivationIndex, getSafeHardenedDerivationPath,
parseDerivedFromParentWithHardenedPath and the single-level regex
sdk-core:
- createWallet peeks derivation-index with ?coin=, expects
{slot, coinType, account}, rejects a coinType that differs from
local statics, and mints multisig and TSS children at the BIP44 path
- ECDSA and EdDSA createSafeChildKeychains take the path; the DKLS
session uses the same 4-level encoding as recovery and every child
is registered at the path. Round 1 still sends the account as
derivationIndex until public-types carries a path (MPC1 follow-up)
- safeKeychain re-derives at the stored BIP44 path, so a leftover
single-level child fails closed
- recovery uses the lib builder and triplet helper
TICKET: WCN-2964
|
|
|
Claude finished @davidkaplanbitgo's task —— View job PR Review: BIP44 Path Migration for Safe Child DerivationThis PR successfully migrates safe child derivation from single-level Code Quality Analysis✅ Excellent Path Validation:
✅ Strong Security Design:
✅ Clean Architecture:
Security AssessmentNo Security Issues Found:
Breaking ChangesAppropriately Scoped: Breaking changes are limited to experimental safe APIs only:
Technical Correctness✅ BIP44 Compliance:
✅ Implementation Quality:
Minor Observations
Recommendation✅ APPROVE - This is a well-implemented security enhancement that properly migrates to standard BIP44 paths while maintaining all security properties. The validation is thorough, the breaking changes are appropriately scoped, and the test coverage is comprehensive. |
Description
Moves safe child derivation from the single-level
m/<n>'scheme to BIP44 paths:m/44'/<coinType>'/<slot>'/<account>'m/44/<coinType>/<slot>/<account>coinTypeis staticsbip44CoinTypeandslotis staticsSAFE_ROOT_SLOT_ORDINALS(1–4).accountis the server's per-(slot, coinType) counter. Nothing is in production, so this is a clean cutover. The SDK keeps no single-level support.This PR also covers the SDK side of SD2 (WCN-2965) and SD3 (WCN-2966), plus the rest of SD4 (WCN-2967). Those tickets are closed as duplicates.
@bitgo/sdk-lib-safesDerivedFromParentWithHardenedPath/DerivedFromParentWithSoftPath) now accept only exact BIP44 paths: 4 levels, purpose 44, slot in the statics ordinals, canonical decimal, every index below 2^31.m/0', wrong depth, wrong purpose, slot 0/5, mixed hardening and leading zeros are all rejected.getSafeBip44CoinType(coin),buildSafeBip44Path(coinType, slot, account)(same signature as the WP builder in BitGo/bitgo-microservices#63403),toSoftTwinPath,parseSafeBip44Path,deriveSafeChildTriplet.parseSafeDerivationIndex,getSafeHardenedDerivationPath,parseDerivedFromParentWithHardenedPathandDERIVED_FROM_PARENT_WITH_HARDENED_PATH(all experimental).@bitgo/sdk-coreSafe.createWalletcallsGET derivation-index?slot=&coin=and expects{slot, coinType, account}back. It rejects the response if the server'scoinTypediffers from the SDK's statics (version skew), before any key is registered. It builds the path and mints both multisig and TSS children at it.createSafeChildKeychainstake the path instead ofderivationIndex.hardenedDerivationPathis gone. The DKLS session uses the same 4-level encoding as recovery (DklsVrfUtils.buildSafeMpcDerivePath).m/${index}'strings are removed.safeKeychainre-derives at the stored BIP44 path. A child stored at a single-level path now fails to re-derive.recovery.tsuses the lib builder and triplet helper instead of its own path builders. Output is unchanged; the existing tests pass without edits.Not in this PR
derivationIndex(set to the account) because the@bitgo/public-typesrequest has nopathfield yet. Two call sites carryTODO(WCN-2969); MPC1 swaps them forpath.childargument fromcreateSafeChildKeychains.Rollout
?coin=peek, the new response shape, and BIP44 path gates.Until those land, safe minting against staging fails. That's expected for the cutover. Draft until then.
Issue Number
WCN-2964
Type of change
createSafeChildKeychainstakespath)How Has This Been Tested?
sdk-lib-safes(81 passing):deriveHardened. The ed25519 deriver reproduces the published 5-level SLIP-0010 vector.sdk-coresafe, wallet, TSS and keychain tests (133 passing):createWalletregisters BIP44 paths on every branch, including ed25519 coins at their own coinType.bitgoECDSAcreateSafeChildKeychains(10 passing):DklsVrfUtils.deriveSafeEcdsaMpcChildat the same path. Mint and offline recovery land on the same key.expressunit suite (1976 passing): the mint route works against the new derivation-index response.bitgo/test/v2/unit/keychains.tshas 8 failing tests (kaspa/starknet seed, OFC key rotation, EdDSA TSS settings mock). The same 8 fail on a cleanmastercheckout.