diff --git a/waddrmgr/scoped_manager.go b/waddrmgr/scoped_manager.go new file mode 100644 index 0000000..28f9975 --- /dev/null +++ b/waddrmgr/scoped_manager.go @@ -0,0 +1,124 @@ +package waddrmgr + +import ( + "fmt" + "sync" + + "github.com/roasbeef/btcd/btcec" + "github.com/roasbeef/btcd/chaincfg" + "github.com/roasbeef/btcutil" + "github.com/roasbeef/btcutil/hdkeychain" + "github.com/roasbeef/btcwallet/internal/zero" + "github.com/roasbeef/btcwallet/walletdb" +) + +// DerivationPath represents a derivation path from a particular key manager's +// scope. Each ScopedKeyManager starts key derivation from the end of their +// cointype hardened key: m/purpose'/cointype'. The fields in this struct allow +// further derivation to the next three child levels after the coin type key. +// This restriction is in the spriti of BIP0044 type derivation. We maintain a +// degree of coherency with the standard, but allow arbitrary derivations +// beyond the cointype key. The key derived using this path will be exactly: +// m/purpose'/cointype'/account/branch/index, where purpose' and cointype' are +// bound by the scope of a particular manager. +type DerivationPath struct { + // Account is the account, or the first immediate child from the scoped + // manager's hardened coin type key. + Account uint32 + + // Branch is the branch to be derived from the account index above. For + // BIP0044-like derivation, this is either 0 (external) or 1 + // (internal). However, we allow this value to vary arbitrarily within + // its size range. + Branch uint32 + + // Index is the final child in the derivation path. This denotes the + // key index within as a child of the account and branch. + Index uint32 +} + +// KeyScope represents a restricted key scope from the primary root key within +// the HD chain. From the root manager (m/) we can create a nearly arbitrary +// number of ScopedKeyManagers of key derivation path: m/purpose'/cointype'. +// These scoped managers can then me managed indecently, as they house the +// encrypted cointype key and can derive any child keys from there on. +type KeyScope struct { + // Purpose is the purpose of this key scope. This is the first child of + // the master HD key. + Purpose uint32 + + // Coin is a value that represents the particular coin which is the + // child of the purpose key. With this key, any accounts, or other + // children can be derived at all. + Coin uint32 +} + +// String returns a human readable version describing the keypath encapsulated +// by the target key scope. +func (k *KeyScope) String() string { + return fmt.Sprintf("m/%v'/%v'", k.Purpose, k.Coin) +} + +// ScopeAddrSchema is the address schema of a particular KeyScope. This will be +// persisted within the database, and will be consulted when deriving any keys +// for a particular scope to know how to encode the public keys as addresses. +type ScopeAddrSchema struct { + // ExternalAddrType is the address type for all keys within branch 0. + ExternalAddrType AddressType + + // InternalAddrType is the address type for all keys within branch 1 + // (change addresses). + InternalAddrType AddressType +} + +var ( + // KeyScopeBIP0049Plus is the key scope of our modified BIP0049 + // derivation. We say this is BIP0049 "plus", as we'll actually use + // p2wkh change all change addresses. + KeyScopeBIP0049Plus = KeyScope{ + Purpose: 49, + Coin: 0, + } + + // KeyScopeBIP0084 is the key scope for BIP0084 derivation. BIP0084 + // will be used to derive all p2wkh addresses. + KeyScopeBIP0084 = KeyScope{ + Purpose: 84, + Coin: 0, + } + + // KeyScopeBIP0044 is the key scope for BIP0044 derivation. Legacy + // wallets will only be able to use this key scope, and no keys beyond + // it. + KeyScopeBIP0044 = KeyScope{ + Purpose: 44, + Coin: 0, + } + + // DefaultKeyScopes is the set of default key scopes that will be + // created by the root manager upon initial creation. + DefaultKeyScopes = []KeyScope{ + KeyScopeBIP0049Plus, + KeyScopeBIP0084, + KeyScopeBIP0044, + } + + // ScopeAddrMap is a map from the default key scopes to the scope + // address schema for each scope type. This will be consulted during + // the initial creation of the root key manager. + ScopeAddrMap = map[KeyScope]ScopeAddrSchema{ + KeyScopeBIP0049Plus: { + ExternalAddrType: NestedWitnessPubKey, + InternalAddrType: WitnessPubKey, + }, + KeyScopeBIP0084: { + ExternalAddrType: WitnessPubKey, + InternalAddrType: WitnessPubKey, + }, + KeyScopeBIP0044: { + InternalAddrType: PubKeyHash, + ExternalAddrType: PubKeyHash, + }, + } +) +