-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
203 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/bitcoinschema/go-bitcoin" | ||
) | ||
|
||
func main() { | ||
xPrivateKey, xPublicKey, err := bitcoin.GenerateHDKeyPair(bitcoin.SecureSeedLength) | ||
if err != nil { | ||
log.Fatalf("error occurred: %s", err.Error()) | ||
} | ||
|
||
// Success! | ||
log.Printf("xPrivateKey: %s \n xPublicKey: %s", xPrivateKey, xPublicKey) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package bitcoin | ||
|
||
import ( | ||
"github.com/bitcoinsv/bsvd/chaincfg" | ||
"github.com/bitcoinsv/bsvutil/hdkeychain" | ||
) | ||
|
||
const ( | ||
// RecommendedSeedLength is the recommended length in bytes for a seed to a master node. | ||
RecommendedSeedLength = 32 // 256 bits | ||
|
||
// SecureSeedLength is the max size of a seed length (most secure | ||
SecureSeedLength = 64 // 512 bits | ||
) | ||
|
||
// GenerateHDKey will create a new master node for use in creating a hierarchical deterministic key chain | ||
func GenerateHDKey(seedLength uint8) (hdKey *hdkeychain.ExtendedKey, err error) { | ||
|
||
// Missing or invalid seed length | ||
if seedLength == 0 { | ||
seedLength = RecommendedSeedLength | ||
} | ||
|
||
// Generate a new seed (added extra security from 256 to 512 bits for seed length) | ||
var seed []byte | ||
if seed, err = hdkeychain.GenerateSeed(seedLength); err != nil { | ||
return | ||
} | ||
|
||
// Generate a new master key | ||
return hdkeychain.NewMaster(seed, &chaincfg.MainNetParams) | ||
} | ||
|
||
// GenerateHDKeyPair will generate a new xPub HD master node (xPrivateKey & xPublicKey) | ||
func GenerateHDKeyPair(seedLength uint8) (xPrivateKey, xPublicKey string, err error) { | ||
|
||
// Generate an HD master key | ||
var masterKey *hdkeychain.ExtendedKey | ||
if masterKey, err = GenerateHDKey(seedLength); err != nil { | ||
return | ||
} | ||
|
||
// Set the xPriv | ||
xPrivateKey = masterKey.String() | ||
|
||
// Create the extended public key | ||
var pubKey *hdkeychain.ExtendedKey | ||
if pubKey, err = masterKey.Neuter(); err != nil { | ||
// Error should nearly never occur since it's using a safely derived masterKey | ||
return | ||
} | ||
|
||
// Set the actual xPub | ||
xPublicKey = pubKey.String() | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package bitcoin | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
) | ||
|
||
// TestGenerateHDKey will test the method GenerateHDKey() | ||
func TestGenerateHDKey(t *testing.T) { | ||
|
||
t.Parallel() | ||
|
||
// Create the list of tests | ||
var tests = []struct { | ||
inputSeed uint8 | ||
expectedNil bool | ||
expectedError bool | ||
}{ | ||
{0, false, false}, | ||
{1, true, true}, | ||
{15, true, true}, | ||
{65, true, true}, | ||
{RecommendedSeedLength, false, false}, | ||
{SecureSeedLength, false, false}, | ||
} | ||
|
||
// Run tests | ||
for _, test := range tests { | ||
if hdKey, err := GenerateHDKey(test.inputSeed); err != nil && !test.expectedError { | ||
t.Errorf("%s Failed: [%d] inputted and error not expected but got: %s", t.Name(), test.inputSeed, err.Error()) | ||
} else if err == nil && test.expectedError { | ||
t.Errorf("%s Failed: [%d] inputted and error was expected", t.Name(), test.inputSeed) | ||
} else if hdKey == nil && !test.expectedNil { | ||
t.Errorf("%s Failed: [%d] inputted and was nil but not expected", t.Name(), test.inputSeed) | ||
} else if hdKey != nil && test.expectedNil { | ||
t.Errorf("%s Failed: [%d] inputted and was NOT nil but expected to be nil", t.Name(), test.inputSeed) | ||
} | ||
} | ||
} | ||
|
||
// ExampleGenerateHDKey example using GenerateHDKey() | ||
func ExampleGenerateHDKey() { | ||
hdKey, err := GenerateHDKey(SecureSeedLength) | ||
if err != nil { | ||
fmt.Printf("error occurred: %s", err.Error()) | ||
return | ||
} | ||
// Cannot show the private/public key since they change each time | ||
fmt.Printf("created HD key successfully! (length: %d)", len(hdKey.String())) | ||
|
||
// Output:created HD key successfully! (length: 111) | ||
} | ||
|
||
// BenchmarkGenerateHDKey benchmarks the method GenerateHDKey() | ||
func BenchmarkGenerateHDKey(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
_, _ = GenerateHDKey(RecommendedSeedLength) | ||
} | ||
} | ||
|
||
// BenchmarkGenerateHDKeySecure benchmarks the method GenerateHDKey() | ||
func BenchmarkGenerateHDKeySecure(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
_, _ = GenerateHDKey(SecureSeedLength) | ||
} | ||
} | ||
|
||
// TestGenerateHDKeyPair will test the method GenerateHDKeyPair() | ||
func TestGenerateHDKeyPair(t *testing.T) { | ||
|
||
t.Parallel() | ||
|
||
// Create the list of tests | ||
var tests = []struct { | ||
inputSeed uint8 | ||
expectedError bool | ||
}{ | ||
{0, false}, | ||
{1, true}, | ||
{15, true}, | ||
{65, true}, | ||
{RecommendedSeedLength, false}, | ||
{SecureSeedLength, false}, | ||
} | ||
|
||
// Run tests | ||
for _, test := range tests { | ||
if privateKey, publicKey, err := GenerateHDKeyPair(test.inputSeed); err != nil && !test.expectedError { | ||
t.Errorf("%s Failed: [%d] inputted and error not expected but got: %s", t.Name(), test.inputSeed, err.Error()) | ||
} else if err == nil && test.expectedError { | ||
t.Errorf("%s Failed: [%d] inputted and error was expected", t.Name(), test.inputSeed) | ||
} else if err == nil && len(privateKey) == 0 { | ||
t.Errorf("%s Failed: [%d] inputted and private key was empty", t.Name(), test.inputSeed) | ||
} else if err == nil && len(publicKey) == 0 { | ||
t.Errorf("%s Failed: [%d] inputted and pubic key was empty", t.Name(), test.inputSeed) | ||
} | ||
} | ||
} | ||
|
||
// ExampleGenerateHDKeyPair example using GenerateHDKeyPair() | ||
func ExampleGenerateHDKeyPair() { | ||
xPrivateKey, xPublicKey, err := GenerateHDKeyPair(SecureSeedLength) | ||
if err != nil { | ||
fmt.Printf("error occurred: %s", err.Error()) | ||
return | ||
} | ||
// Cannot show the private/public key since they change each time | ||
fmt.Printf("created HD key successfully! (xPrivateKey length: %d) (xPublicKey length: %d)", len(xPrivateKey), len(xPublicKey)) | ||
|
||
// Output:created HD key successfully! (xPrivateKey length: 111) (xPublicKey length: 111) | ||
} | ||
|
||
// BenchmarkGenerateHDKeyPair benchmarks the method GenerateHDKeyPair() | ||
func BenchmarkGenerateHDKeyPair(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
_, _, _ = GenerateHDKeyPair(RecommendedSeedLength) | ||
} | ||
} | ||
|
||
// BenchmarkGenerateHDKeyPairSecure benchmarks the method GenerateHDKeyPair() | ||
func BenchmarkGenerateHDKeyPairSecure(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
_, _, _ = GenerateHDKeyPair(SecureSeedLength) | ||
} | ||
} |