solana-web3.js icon indicating copy to clipboard operation
solana-web3.js copied to clipboard

(code included) Add getHDKeypairs()

Open mikemaccana opened this issue 2 years ago • 5 comments

Motivation

Solana CLI includes a function to get HD keypairs from a seed. web3.js should do the same.

Example use case

A user wishes to get HD keypairs. They hunt around, and end up getting a code snippet from Solana cookbook or similar. The cookbook asks users to use various magic numbers (44, 501 and 0), with no explanation so the user isn't confident in the process.

Rather than ask every user to copypaste the same snippet, it's better we include this in web3.js.

This code is for both browsers and node so belongs in the main web3.js.

Details

As with the new getProgramDerivedAddress we can use get here - avoiding the need to for users to remember a more specific verb like derive.

import { derivePath } from "ed25519-hd-key";

// See https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki 
const PURPOSE = 44;
const SOLANA_COIN_TYPE = 501;
const NON_CHANGE_ADDRESS = 0;

export const getHDKeypairs = async (seed: UInt8Array, count: number): Array<Keypair> => {
  // The seed is the parent to many wallets
  // See https://github.com/solana-labs/solana/blob/master/web3.js/examples/get_account_info.js
  const seed = await bip39.mnemonicToSeed(mnemonic, password);

  const keyPairs: Array<Keypair> = [];

  for (let accountIndex = 0; accountIndex < count; accountIndex++) {
    const path = `m/${PURPOSE}'/${SOLANA_COIN_TYPE}'/${accountIndex}'/${NON_CHANGE_ADDRESS}'`;
    const keypair = Keypair.fromSeed(derivePath(path, seed.toString("hex")).key);
    keyPairs.push(keypair);
  }
  return keyPairs;
};

mikemaccana avatar Sep 15 '23 12:09 mikemaccana

This would be useful, but needs to clarify where derivePath comes from and the other packages

nickfrosty avatar Sep 20 '23 13:09 nickfrosty

Good point Nick. I've updated the example to include the derivePath() dependency. @steveluscher how do you feel about ed25519-hd-key being a web3.js dependency? It's small but depends on Tweetnacl so we might actually want to rebuild ed25519-hd-key using webcrypto per the rest of the new web3.js.

mikemaccana avatar Sep 21 '23 09:09 mikemaccana

I remember there were loads of efforts to move away from the tweetnacl package, so I don't think anyone wants to add it back in. Do the @noble/curves have the functionality to do this instead?

nickfrosty avatar Sep 21 '23 12:09 nickfrosty

…how do you feel about ed25519-hd-key being a web3.js dependency?

Definitely, definitely not, but someone should absolutely release a package that creates the seed as you've outlined above! You can then use that with crypto.subtle.importKey(). No web3.js required.

What we will likely include in web3.js:

  • A key bytes import function that simplifies the process of creating a PKCS#8 payload and generating a CryptoKey from it.
  • An importKey() polyfill to @solana/webcrypto-ed25519-polyfill (#1621).

Given those two things, anyone can easily build an HD key generator that produces CryptoKey instances compatible with the new web3.js.

steveluscher avatar Sep 21 '23 18:09 steveluscher

If, on the other hand, we can build an HD key generator from the ground up using the SubtleCrypto builtins, then maybe we should consider rolling the whole thing into @solana/keys.

steveluscher avatar Sep 21 '23 18:09 steveluscher

Things we won't do:

  • include bip32 as a dependency of web3.js
  • include any HD derivation package as a dependency of web3.js (looks like the contemporary one is micro-key-producer)

Things we could do:

  • create a path helper (ie. getDerivationPathForIndex()) in @solana/keys

Feel free to send a PR for that, but I feel like it won't scratch this itch, given that it only solves 1% of the problem.

steveluscher avatar Oct 25 '24 00:10 steveluscher

Because there has been no activity on this issue for 7 days since it was closed, it has been automatically locked. Please open a new issue if it requires a follow up.

github-actions[bot] avatar Nov 01 '24 08:11 github-actions[bot]