Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tooling] SLIP-0010 HD Child Key Generation #510

Merged
merged 39 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2f14790
Implement SLIP-0010 key derivation
h5law Feb 11, 2023
d27b260
Add SLIPS test cases
h5law Feb 14, 2023
ff4f93a
Add endpoints to interact with slips keys
h5law Feb 14, 2023
5736220
Reduce scope
h5law Feb 14, 2023
459edf7
Add GetSeed() function
h5law Feb 14, 2023
4b7fe83
Update docs
h5law Feb 14, 2023
db1a2dc
Change SLIPS to SLIP
h5law Feb 14, 2023
4f4dc10
Address linter errors
h5law Feb 14, 2023
2ae5eda
Merge branch 'main' into slip-0010-keys
h5law Feb 14, 2023
f99a56e
Remove BIP-44 paths
h5law Feb 21, 2023
aaa86a1
Link to SLIP spec
h5law Feb 21, 2023
6c9601d
Address comments
h5law Feb 21, 2023
24dd94c
Add SLIP-0010 test vectors
h5law Feb 21, 2023
962ba1d
Add BIP-44 paths back in
h5law Feb 21, 2023
c82cd0e
Update go.mod
h5law Feb 21, 2023
879eb17
Merge branch 'main' into slip-0010-keys
h5law Feb 21, 2023
10312e2
Add comments to clarify test vectors
h5law Feb 22, 2023
6675cd7
Merge branch 'main' into slip-0010-keys
h5law Feb 23, 2023
644b614
Fix merge error
h5law Feb 23, 2023
7024b64
Add DeriveChild method to KeyPair interface
h5law Feb 23, 2023
8bf2eb6
Combine test vectors
h5law Feb 23, 2023
35fbacb
Update graphs
h5law Feb 23, 2023
851c9c1
Address comments
h5law Feb 23, 2023
645be44
Add pokt specific test vectors
h5law Feb 23, 2023
e339e23
Add deriveChild CLI endpoint
h5law Feb 23, 2023
5e34cd5
Return (KeyPair, error) when storing derived child
h5law Feb 23, 2023
9a23603
Fix tests
h5law Feb 23, 2023
8a51fcd
make generate_cli_commands_docs
h5law Feb 23, 2023
749c3cf
Address comments
h5law Feb 24, 2023
fb6f3b1
make generate_cli_commands_docs
h5law Feb 24, 2023
9b9da19
Address linter error
h5law Feb 24, 2023
2df7edf
Update comments to match godoc format
h5law Feb 24, 2023
a667312
Merge branch 'main' into slip-0010-keys
h5law Feb 24, 2023
d93431d
Remove viper binding and pass store as argument to function
h5law Feb 26, 2023
b9fa9dd
Merge branch 'main' into slip-0010-keys
h5law Feb 26, 2023
3057fda
Address comments
h5law Feb 27, 2023
4282c91
Update comments
h5law Feb 28, 2023
69b310a
Update CHANGELOG.md files
h5law Feb 28, 2023
61aece6
Fix linter error
h5law Feb 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/client/keybase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This document is intended to outline the current Keybase implementation used by
- [Keybase Code Structure](#keybase-code-structure)
- [Makefile Testing Helper](#makefile-testing-helper)
- [KeyPair Encryption \& Armouring](#keypair-encryption--armouring)
- [SLIP-0010 Child Key Generation](#child-key-generation)
- [TODO: Future Work](#todo-future-work)

_TODO(#150): The current keybase has not been integrated with any CLI endpoints, and as such is only accessible through the [keybase interface](#keybase-interface)_
Expand Down Expand Up @@ -73,6 +74,10 @@ The [documentation in the crypto library](../../../shared/crypto/README.md) cove

The primitives and functions defined there are heavily used throughout this package.

## Child Key Generation

The [documentation in the crypto library](../../../shared/crypto/README.md) covers the specifics of the [SLIPS-0010](https://github.com/satoshilabs/slips/blob/master/slip-0010.md) implementation related to child key generation from a single master key

## TODO: Future Work

- [ ] Improve error handling and error messages for importing keys with invalid strings/invalid JSON
Expand Down
8 changes: 8 additions & 0 deletions app/client/keybase/keybase.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ type Keybase interface {
// Insert a new keypair from the JSON string of the encrypted private key into the DB
ImportFromJSON(jsonStr, passphrase string) error

// SLIPS-0010 Key Derivation
// Deterministically generate and return the derived child key
DeriveChildFromKey(masterAddrHex, passphrase string, childIndex uint32) (crypto.KeyPair, error)
h5law marked this conversation as resolved.
Show resolved Hide resolved
DeriveChildFromSeed(seed []byte, childIndex uint32) (crypto.KeyPair, error)
// Deterministically generate and store the derived child key in the keybase
StoreChildFromKey(masterAddrHex, masterPassphrase string, childIndex uint32, childPassphrase, childHint string) error
StoreChildFromSeed(seed []byte, childIndex uint32, childPassphrase, childHint string) error

// Accessors
Get(address string) (crypto.KeyPair, error)
GetPubKey(address string) (crypto.PublicKey, error)
Expand Down
80 changes: 80 additions & 0 deletions app/client/keybase/keystore.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,86 @@ func (keybase *badgerKeybase) GetAll() (addresses []string, keyPairs []crypto.Ke
return addresses, keyPairs, nil
}

// Deterministically generate and return the ith child from the seed provided
func (keybase *badgerKeybase) DeriveChildFromSeed(seed []byte, childIndex uint32) (crypto.KeyPair, error) {
path := fmt.Sprintf(crypto.PoktAccountPathFormat, childIndex)
childKey, err := crypto.DeriveChild(path, seed)
if err != nil {
return nil, err
}
return childKey, nil
}

// Deterministically generate and return the ith child key from the masterAddrHex key stored in the keybase
func (keybase *badgerKeybase) DeriveChildFromKey(masterAddrHex, passphrase string, childIndex uint32) (crypto.KeyPair, error) {
privKey, err := keybase.GetPrivKey(masterAddrHex, passphrase)
if err != nil {
return nil, err
}
seed := privKey.Seed()
return keybase.DeriveChildFromSeed(seed, childIndex)
}

// Deterministically generate and store the ith child from the masterAddrHex key stored in the keybase
func (keybase *badgerKeybase) StoreChildFromSeed(seed []byte, childIndex uint32, childPassphrase, childHint string) error {
path := fmt.Sprintf(crypto.PoktAccountPathFormat, childIndex)
h5law marked this conversation as resolved.
Show resolved Hide resolved
childKey, err := crypto.DeriveChild(path, seed)
if err != nil {
return err
}
// No need to re-encrypt with provided passphrase
if childPassphrase == "" && childHint == "" {
err = keybase.db.Update(func(tx *badger.Txn) error {
h5law marked this conversation as resolved.
Show resolved Hide resolved
// Use key address as key in DB
addrKey := childKey.GetAddressBytes()

// Encode KeyPair into []byte for value
keypairBz, err := childKey.Marshal()
if err != nil {
return err
}

return tx.Set(addrKey, keypairBz)
})
return err
}

// Re-encrypt child key with passphrase and hint
return keybase.db.Update(func(tx *badger.Txn) error {
// Get the private key hex string from the child key
privKeyHex, err := childKey.ExportString("") // No passphrase by default
if err != nil {
return err
}

keyPair, err := crypto.CreateNewKeyFromString(privKeyHex, childPassphrase, childHint)
if err != nil {
return err
}

// Use key address as key in DB
addrKey := keyPair.GetAddressBytes()

// Encode KeyPair into []byte for value
keypairBz, err := keyPair.Marshal()
if err != nil {
return err
}

return tx.Set(addrKey, keypairBz)
})
}

// Deterministically generate and store the ith child from the masterAddrHex key stored in the keybase
func (keybase *badgerKeybase) StoreChildFromKey(masterAddrHex, masterPassphrase string, childIndex uint32, childPassphrase, childHint string) error {
masterPrivKey, err := keybase.GetPrivKey(masterAddrHex, masterPassphrase)
if err != nil {
return err
}
seed := masterPrivKey.Seed()
return keybase.StoreChildFromSeed(seed, childIndex, childPassphrase, childHint)
}

// Check whether an address is currently stored in the DB
func (keybase *badgerKeybase) Exists(address string) (bool, error) {
val, err := keybase.Get(address)
Expand Down
Loading