How can I use Hedera JS SDK to generate a set of ECDSA key-pairs based on a BIP-39 seed phrase and a custom derivation path?

huangapple go评论100阅读模式
英文:

How can I use Hedera JS SDK to generate a set of ECDSA key-pairs based on a BIP-39 seed phrase and a custom derivation path?

问题

I understand your request. Here's the translated portion:

  1. 我目前正在使用Hedera JS SDK来直接将私钥作为输入生成单个ECDSA密钥对如下所示
  2. ```js
  3. const privateKey = PrivateKey.fromStringECDSA(process.env.TARGET_HEX_PRIVATE_KEY);

相反,我想要像这样做,使用BIP-39种子短语和派生路径作为输入:

  1. const mnemonic = Mnemonic.fromString(process.env.TARGET_SEED_PHRASE);
  2. const privateKey = await mnemonic.toEcdsaPrivateKey('', "m/44'/60'/0'/0/0");

但是,MnemonictoEcdsaPrivateKey函数似乎根据其JsDoc @param注释接受一个数字数组作为派生路径的输入,如下所示:

  1. /**
  2. * 从这个助记短语中恢复ECDSA私钥,可选的口令。
  3. *
  4. * @param {string} [passphrase]
  5. * @param {number[]} [path]
  6. * @returns {Promise<PrivateKey>}
  7. */
  8. async toEcdsaPrivateKey(passphrase = "", path) {
  9. return CACHE.privateKeyConstructor(
  10. await this._mnemonic.toEcdsaPrivateKey(passphrase, path)
  11. );
  12. }

在我的用例中,我想要使用MetaMask,不幸的是,MetaMask目前还不支持根据网络配置进行自定义派生路径,并且硬编码以太坊派生路径为m/44'/60'/0'/0/0。请注意,前3个段是“hardened”,而后面的2个不是。

如何指定这个派生路径呢?

  1. <details>
  2. <summary>英文:</summary>
  3. I&#39;m currently using the Hedera JS SDK to generate a single ECDSA key-pair using a private key directly as an input, like so:
  4. ```js
  5. const privateKey = PrivateKey.fromStringECDSA(process.env.TARGET_HEX_PRIVATE_KEY);

Instead I would like to do something like this instead, where I am using a BIP-39 seed phrase and a derivation path as inputs:

  1. const mnemonic = Mnemonic.fromString(process.env.TARGET_SEED_PHRASE);
  2. const privateKey = await mnemonic.toEcdsaPrivateKey(&#39;&#39;, &quot;m/44&#39;/60&#39;/0&#39;/0/0&quot;);

However, Mnemonic's toEcdsaPrivateKey function seems to accept an array of numbers as the input for the derivation path, based on its JsDoc @param comment, copied below:

  1. /**
  2. * Recover an ECDSA private key from this mnemonic phrase, with an
  3. * optional passphrase.
  4. *
  5. * @param {string} [passphrase]
  6. * @param {number[]} [path]
  7. * @returns {Promise&lt;PrivateKey&gt;}
  8. */
  9. async toEcdsaPrivateKey(passphrase = &quot;&quot;, path) {
  10. return CACHE.privateKeyConstructor(
  11. await this._mnemonic.toEcdsaPrivateKey(passphrase, path)
  12. );
  13. }

In my use case, I would like to work with MetaMask, which unfortunately does not yet support custom derivation paths per network configuration, and hardcodes the Ethereum derivation path of m/44&#39;/60&#39;/0&#39;/0/0 instead. Note that the first 3 segments are "hardened", while the remaining 2 are not.

How can I specify this derivation path?

答案1

得分: 5

In the latest release, v2.24.1,
the Mnemonic class has been updated to deprecate
toEcdsaPrivateKey:

  1. /**
  2. * @deprecated - Use `toStandardEd25519PrivateKey()` or `toStandardECDSAsecp256k1PrivateKey()` instead
  3. * Recover an ECDSA private key from this mnemonic phrase, with an
  4. * optional passphrase.
  5. * @param {string} [passphrase]
  6. * @param {number[]} [path]
  7. * @returns {Promise&lt;PrivateKey&gt;}
  8. */

... so using the methods suggested by @Topaco in the comments,
where each hardened segment is binary OR-ed with 0x80000000,
is not going to work.
... and therefore not possible to achieve my intended outcome
using only Hedera JS SDK.

So here's a workaround that uses EthersJs in combination
with the Hedera JS SDK to achieve the intended outcome:

  1. import { PrivateKey } from "@hashgraph/sdk";
  2. import { utils as ethersUtils } from "ethers";
  3. // init a hierarchically deterministic wallet's node using a seed phrase
  4. const hdNodeRoot = ethersUtils.HDNode.fromMnemonic(process.env.TARGET_SEED_PHRASE);
  5. // apply the derivation path, `accountIdx` starts at `0`
  6. const hdNodeX = hdNodeRoot.derivePath(`m/44'/60'/0'/0/${accountIdx}`);
  7. // convert from ethersjs private key to hedera js sdk private key
  8. const privateKeyX = PrivateKey.fromStringECDSA(hdNodeX.privateKey);
  9. // extract the `0x...` address from the private key
  10. const addressX = privateKeyX.publicKey.toEvmAddress();

The significant bit is where utils.HDNode.fromMnemonic from EthersJs
is used in place of Mnemonic.toEcdsaPrivateKey from Hedera JS SDK.


Here's a more complete example,
where I create multiple accounts using the above method,
and fund them from an ED22519 account
(originally generated on and funded by the Hedera Testnet Portal,
which sort of functions like a faucet).

英文:

In the latest release, v2.24.1,
the Mnemonic class has been updated to deprecate
toEcdsaPrivateKey:

  1. /**
  2. * @deprecated - Use `toStandardEd25519PrivateKey()` or `toStandardECDSAsecp256k1PrivateKey()` instead
  3. * Recover an ECDSA private key from this mnemonic phrase, with an
  4. * optional passphrase.
  5. * @param {string} [passphrase]
  6. * @param {number[]} [path]
  7. * @returns {Promise&lt;PrivateKey&gt;}
  8. */

... so using the methods suggested by @Topaco in the comments,
where each hardened segment is binary OR-ed with 0x80000000,
is not going to work.
... and therefore not possible to achieve my intended outcome
using only Hedera JS SDK.

So here's a workaround that uses EthersJs in combination
with the Hedera JS SDK to achieve the intended outcome:

  1. import { PrivateKey } from &quot;@hashgraph/sdk&quot;;
  2. import { utils as ethersUtils } from &quot;ethers&quot;;
  3. // init a hierarchically deterministic wallet&#39;s node using a seed phrase
  4. const hdNodeRoot = ethersUtils.HDNode.fromMnemonic(process.env.TARGET_SEED_PHRASE);
  5. // apply the derivation path, `accountIdx` starts at `0`
  6. const hdNodeX = hdNodeRoot.derivePath(`m/44&#39;/60&#39;/0&#39;/0/${accountIdx}`);
  7. // convert from ethersjs private key to hedera js sdk private key
  8. const privateKeyX = PrivateKey.fromStringECDSA(hdNodeX.privateKey);
  9. // extract the `0x...` address from the private key
  10. const addressX = privateKeyX.publicKey.toEvmAddress();

The significant bit is where utils.HDNode.fromMnemonic from EthersJs
is used in place of Mnemonic.toEcdsaPrivateKey from Hedera JS SDK.


Here's a more complete example,
where I create multiple accounts using the above method,
and fund them from an ED22519 account
(originally generated on and funded by the Hedera Testnet Portal,
which sort of functions like a faucet).

huangapple
  • 本文由 发表于 2023年4月13日 15:27:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76002731.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定