Files
keyfunc/internal/childmnemonic/childmnemonic_test.go
T
sneak 4e1258302f
check / check (push) Successful in 52s
Move the Go module to sneak.berlin/go/keyfunc (closes #15)
REPO_POLICIES.md sets the Go module root to sneak.berlin/go/<name>.
go.mod, every import of the old path and the -X path in the Makefile
LDFLAGS now use sneak.berlin/go/keyfunc; make fmt moved those imports
to their new place in the sort order. The old path keeps no alias. The
README gives the go install line next to the build from a clone and
drops this issue from its TODO list, which now names the open 1.0
issues.

Model: opus-5-5
2026-10-03 13:10:29 +00:00

118 lines
3.3 KiB
Go

package childmnemonic_test
import (
"strings"
"testing"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/stretchr/testify/require"
bip39 "github.com/tyler-smith/go-bip39"
"sneak.berlin/go/keyfunc/internal/childmnemonic"
"sneak.berlin/go/keyfunc/internal/derive"
)
// The lengths the tool offers, and one it does not.
const (
twelve = 12
eighteen = 18
twentyFour = 24
fifteen = 15
)
// specificationKey is the master key the BIP-85 specification gives
// every one of its test vectors for.
const specificationKey = "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBq" +
"sx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb"
// The three English child mnemonics at key index 0 that the BIP-85
// specification gives for that master key.
const (
twelveWords = "girl mad pet galaxy egg matter matrix prison refuse " +
"sense ordinary nose"
eighteenWords = "near account window bike charge season chef number " +
"sketch tomorrow excuse sniff circle vital hockey outdoor " +
"supply token"
twentyFourWords = "puppy ocean match cereal symbol another shed " +
"magic wrap hammer bulb intact gadget divorce twin tonight " +
"reason outdoor destroy simple truth cigar social volcano"
)
// example returns the mnemonic every BIP-39 document uses to show its
// test vectors: eleven abandons and about.
func example() string {
return strings.Repeat("abandon ", 11) + "about"
}
func TestTheSpecificationTestVectors(t *testing.T) {
t.Parallel()
require.Equal(t, twelveWords, fromSpecificationKey(t, twelve))
require.Equal(t, eighteenWords, fromSpecificationKey(t, eighteen))
require.Equal(t, twentyFourWords, fromSpecificationKey(t, twentyFour))
}
func TestTheLongestChildMnemonicPassesItsOwnChecksum(t *testing.T) {
t.Parallel()
child := fromSpecificationKey(t, twentyFour)
require.Len(t, strings.Fields(child), twentyFour)
require.True(t, bip39.IsMnemonicValid(child))
}
func TestEachKeyIndexGivesItsOwnChildMnemonic(t *testing.T) {
t.Parallel()
master, err := derive.Master(example())
require.NoError(t, err)
first, err := childmnemonic.Derive(master, twelve, 0)
require.NoError(t, err)
require.True(t, bip39.IsMnemonicValid(first))
second, err := childmnemonic.Derive(master, twelve, 1)
require.NoError(t, err)
require.True(t, bip39.IsMnemonicValid(second))
require.NotEqual(t, first, second)
}
func TestALengthTheToolDoesNotOfferIsRefused(t *testing.T) {
t.Parallel()
master, err := hdkeychain.NewKeyFromString(specificationKey)
require.NoError(t, err)
_, err = childmnemonic.Derive(master, fifteen, 0)
require.ErrorIs(t, err, childmnemonic.ErrWordCount)
}
func TestAnIndexWithNoHardenedChildIsRefused(t *testing.T) {
t.Parallel()
master, err := hdkeychain.NewKeyFromString(specificationKey)
require.NoError(t, err)
_, err = childmnemonic.Derive(master, twelve, derive.MaxIndex+1)
require.ErrorIs(t, err, derive.ErrIndexTooLarge)
_, err = childmnemonic.Derive(master, twelve, derive.MaxIndex)
require.NoError(t, err)
}
// fromSpecificationKey derives the child mnemonic of that length at key
// index 0 from the master key the specification gives.
func fromSpecificationKey(t *testing.T, words uint32) string {
t.Helper()
master, err := hdkeychain.NewKeyFromString(specificationKey)
require.NoError(t, err)
child, err := childmnemonic.Derive(master, words, 0)
require.NoError(t, err)
return child
}