You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Split out from #2573 per the discussion with @allocz. #2545 added scalar zeroing on the wif.go decode path; this issue tracks the broader concern @allocz raised: private-key material that transits math/big.Int cannot be reliably scrubbed from memory.
Why big.Int is a problem for secrets
big.Int stores its magnitude in an internal nat ([]Word) slice that can be grown/reallocated by arithmetic, and there is no exported way to zero the backing store. So even when a caller zeroes its own key byte slice, a copy of the secret can linger in the heap inside intermediate big.Int values until GC (and possibly beyond).
Concrete paths still using big.Int on secret material
btcutil/hdkeychain/extendedkey.go:
DeriveNonStandard (~L419–430): ilNum := new(big.Int).SetBytes(il), then ilNum.Add(keyNum) / ilNum.Mod(N) / ilNum.Bytes() — both the intermediate IL and the parent private key pass through big.Int.
NewMaster (~L673): secretKeyNum := new(big.Int).SetBytes(secretKey) on the HMAC-derived master secret.
NewKeyFromString (~L720): keyNum := new(big.Int).SetBytes(keyData) on the deserialized private key.
Precedent already in-tree
The standard Child() derivation was already migrated away from big.Int to btcec.ModNScalar (fixed-size, zeroable) — see the // as the old big.Int usage in this area of the codebase comment around L324. So the remediation direction is established and accepted; these three paths just weren't converted.
Proposed scope
Convert the secret paths above from big.Int to btcec.ModNScalar (or fixed 32-byte arrays with explicit zero()), mirroring Child().
Grep-audit remaining secret-bearing big.Int uses beyond hdkeychain (ECDSA nonce handling, WIF, any key (de)serialization) and list them here before touching code.
runtime/secret (as @allocz noted) could help but is still experimental — not proposing to depend on it here.
Before opening PRs I'd like a maintainer to confirm appetite and whether DeriveNonStandard in particular is in scope (it's the legacy issue-172 path). Refs #2573, #2545.
Split out from #2573 per the discussion with @allocz. #2545 added scalar zeroing on the
wif.godecode path; this issue tracks the broader concern @allocz raised: private-key material that transitsmath/big.Intcannot be reliably scrubbed from memory.Why
big.Intis a problem for secretsbig.Intstores its magnitude in an internalnat([]Word) slice that can be grown/reallocated by arithmetic, and there is no exported way to zero the backing store. So even when a caller zeroes its own key byte slice, a copy of the secret can linger in the heap inside intermediatebig.Intvalues until GC (and possibly beyond).Concrete paths still using
big.Inton secret materialbtcutil/hdkeychain/extendedkey.go:DeriveNonStandard(~L419–430):ilNum := new(big.Int).SetBytes(il), thenilNum.Add(keyNum)/ilNum.Mod(N)/ilNum.Bytes()— both the intermediateILand the parent private key pass throughbig.Int.NewMaster(~L673):secretKeyNum := new(big.Int).SetBytes(secretKey)on the HMAC-derived master secret.NewKeyFromString(~L720):keyNum := new(big.Int).SetBytes(keyData)on the deserialized private key.Precedent already in-tree
The standard
Child()derivation was already migrated away frombig.Inttobtcec.ModNScalar(fixed-size, zeroable) — see the// as the old big.Int usage in this area of the codebasecomment around L324. So the remediation direction is established and accepted; these three paths just weren't converted.Proposed scope
big.Inttobtcec.ModNScalar(or fixed 32-byte arrays with explicitzero()), mirroringChild().big.Intuses beyond hdkeychain (ECDSA nonce handling, WIF, any key (de)serialization) and list them here before touching code.wif.gozeroing from btcutil/wif.go: private key material not zeroed in several code paths #2573 / btcutil: reject out-of-range private keys in DecodeWIF #2545 as the tracked baseline.runtime/secret(as @allocz noted) could help but is still experimental — not proposing to depend on it here.Before opening PRs I'd like a maintainer to confirm appetite and whether
DeriveNonStandardin particular is in scope (it's the legacy issue-172 path). Refs #2573, #2545.