func verifySeed() error { seed := new([32]byte) err := promptSeed(seed) if err != nil { return err } // Derive the master extended key from the seed. root, err := hdkeychain.NewMaster(seed[:], hdPrivateKeyID) if err != nil { return err } defer root.Zero() // Derive the cointype key according to BIP0044. coinTypeKeyPriv, err := deriveCoinTypeKey(root, hdCoinType) if err != nil { return err } defer coinTypeKeyPriv.Zero() // Derive the account key for the first account according to BIP0044. acctKeyPriv, err := deriveAccountKey(coinTypeKeyPriv, 0) if err != nil { // The seed is unusable if the any of the children in the // required hierarchy can't be derived due to invalid child. if err == hdkeychain.ErrInvalidChild { return fmt.Errorf("the provided seed is unusable") } return err } // Ensure the branch keys can be derived for the provided seed according // to BIP0044. if err := checkBranchKeys(acctKeyPriv); err != nil { // The seed is unusable if the any of the children in the // required hierarchy can't be derived due to invalid child. if err == hdkeychain.ErrInvalidChild { return fmt.Errorf("the provided seed is unusable") } return err } // The address manager needs the public extended key for the account. acctKeyPub, err := acctKeyPriv.Neuter() if err != nil { return fmt.Errorf("failed to convert private key for account 0") } index := uint32(0) // First address branch := uint32(0) // External // The next address can only be generated for accounts that have already // been created. acctKey := acctKeyPub defer acctKey.Zero() // Derive the appropriate branch key and ensure it is zeroed when done. branchKey, err := acctKey.Child(branch) if err != nil { return err } defer branchKey.Zero() // Ensure branch key is zeroed when done. key, err := branchKey.Child(index) if err != nil { return err } defer key.Zero() addr, err := key.Address(pubKeyHashAddrID) if err != nil { return err } fmt.Printf("First derived address of given seed: \n%v\n", addr.EncodeAddress()) // Zero the seed array. copy(seed[:], bytes.Repeat([]byte{0x00}, 32)) return nil }
// generateSeed derives an address from an HDKeychain for use in wallet. It // outputs the seed, address, and extended public key to the file specified. func generateSeed(filename string) error { seed, err := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen) if err != nil { return err } // Derive the master extended key from the seed. root, err := hdkeychain.NewMaster(seed, HDPrivateKeyID) if err != nil { return err } // Derive the cointype key according to BIP0044. coinTypeKeyPriv, err := deriveCoinTypeKey(root, HDCoinType) if err != nil { return err } // Derive the account key for the first account according to BIP0044. acctKeyPriv, err := deriveAccountKey(coinTypeKeyPriv, 0) if err != nil { // The seed is unusable if the any of the children in the // required hierarchy can't be derived due to invalid child. if err == hdkeychain.ErrInvalidChild { return fmt.Errorf("the provided seed is unusable") } return err } // Ensure the branch keys can be derived for the provided seed according // to BIP0044. if err := checkBranchKeys(acctKeyPriv); err != nil { // The seed is unusable if the any of the children in the // required hierarchy can't be derived due to invalid child. if err == hdkeychain.ErrInvalidChild { return fmt.Errorf("the provided seed is unusable") } return err } // The address manager needs the public extended key for the account. acctKeyPub, err := acctKeyPriv.Neuter() if err != nil { return fmt.Errorf("failed to convert private key for account 0") } index := uint32(0) // First address branch := uint32(0) // External // The next address can only be generated for accounts that have already // been created. acctKey := acctKeyPub // Derive the appropriate branch key and ensure it is zeroed when done. branchKey, err := acctKey.Child(branch) if err != nil { return err } defer branchKey.Zero() // Ensure branch key is zeroed when done. key, err := branchKey.Child(index) if err != nil { return err } addr, err := key.Address(PubKeyHashAddrID) if err != nil { return err } var buf bytes.Buffer buf.WriteString("First address: ") buf.WriteString(addr.EncodeAddress()) buf.WriteString("\n") buf.WriteString("Extended public key: ") acctKeyStr, err := acctKey.String() if err != nil { return err } buf.WriteString(acctKeyStr) buf.WriteString("\n") buf.WriteString("Seed: ") seedStr, err := pgpwordlist.ToStringChecksum(seed) if err != nil { return err } buf.WriteString(seedStr) buf.WriteString("\n") buf.WriteString("Seed hex: ") buf.WriteString(fmt.Sprintf("%x", seed)) buf.WriteString("\n") err = writeNewFile(filename, buf.Bytes(), 0644) if err != nil { return err } return nil }
// generateSeed derives an address from an HDKeychain for use in wallet. It // outputs the seed, address, and extended public key to the file specified. func generateSeed(filename string) error { seed, err := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen) if err != nil { return err } // Derive the master extended key from the seed. root, err := hdkeychain.NewMaster(seed, hdPrivateKeyID) if err != nil { return err } defer root.Zero() // Derive the cointype key according to BIP0044. coinTypeKeyPriv, err := deriveCoinTypeKey(root, hdCoinType) if err != nil { return err } defer coinTypeKeyPriv.Zero() // Derive the account key for the first account according to BIP0044. acctKeyPriv, err := deriveAccountKey(coinTypeKeyPriv, 0) if err != nil { // The seed is unusable if the any of the children in the // required hierarchy can't be derived due to invalid child. if err == hdkeychain.ErrInvalidChild { return fmt.Errorf("the provided seed is unusable") } return err } // Ensure the branch keys can be derived for the provided seed according // to BIP0044. if err := checkBranchKeys(acctKeyPriv); err != nil { // The seed is unusable if the any of the children in the // required hierarchy can't be derived due to invalid child. if err == hdkeychain.ErrInvalidChild { return fmt.Errorf("the provided seed is unusable") } return err } // The address manager needs the public extended key for the account. acctKeyPub, err := acctKeyPriv.Neuter() if err != nil { return fmt.Errorf("failed to convert private key for account 0") } index := uint32(0) // First address branch := uint32(0) // External // The next address can only be generated for accounts that have already // been created. acctKey := acctKeyPub defer acctKey.Zero() // Derive the appropriate branch key and ensure it is zeroed when done. branchKey, err := acctKey.Child(branch) if err != nil { return err } defer branchKey.Zero() // Ensure branch key is zeroed when done. key, err := branchKey.Child(index) if err != nil { return err } defer key.Zero() addr, err := key.Address(pubKeyHashAddrID) if err != nil { return err } // Require the user to write down the seed. reader := bufio.NewReader(os.Stdin) seedStr, err := pgpwordlist.ToStringChecksum(seed) if err != nil { return err } seedStrSplit := strings.Split(seedStr, " ") fmt.Println("WRITE DOWN THE SEED GIVEN BELOW. YOU WILL NOT BE GIVEN " + "ANOTHER CHANCE TO.\n") fmt.Printf("Your wallet generation seed is:\n\n") for i := 0; i < hdkeychain.RecommendedSeedLen+1; i++ { fmt.Printf("%v ", seedStrSplit[i]) if (i+1)%6 == 0 { fmt.Printf("\n") } } fmt.Printf("\n\nHex: %x\n", seed) fmt.Println("IMPORTANT: Keep the seed in a safe place as you\n" + "will NOT be able to restore your wallet without it.") fmt.Println("Please keep in mind that anyone who has access\n" + "to the seed can also restore your wallet thereby\n" + "giving them access to all your funds, so it is\n" + "imperative that you keep it in a secure location.\n") for { fmt.Print("Once you have stored the seed in a safe \n" + "and secure location, enter OK here to erase the \n" + "seed and all derived keys from memory. Derived \n" + "public keys and an address will be stored in the \n" + "file specified (default: keys.txt): ") confirmSeed, err := reader.ReadString('\n') if err != nil { return err } confirmSeed = strings.TrimSpace(confirmSeed) confirmSeed = strings.Trim(confirmSeed, `"`) if confirmSeed == "OK" { break } } var buf bytes.Buffer buf.WriteString("First address: ") buf.WriteString(addr.EncodeAddress()) buf.WriteString("\n") buf.WriteString("Extended public key: ") acctKeyStr, err := acctKey.String() if err != nil { return err } buf.WriteString(acctKeyStr) buf.WriteString("\n") // Zero the seed array. copy(seed[:], bytes.Repeat([]byte{0x00}, 32)) err = writeNewFile(filename, buf.Bytes(), 0644) if err != nil { return err } return nil }