Esempio n. 1
0
// 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
}
Esempio n. 2
0
// 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
}