Login with mnemonic is incorrectly creating the private key from entropy instead of from seed. #729

Open
opened 2024-01-28 20:40:06 +00:00 by CryptoDrew · 0 comments

Description

The file src/branch/main/packages/app/src/Hooks/useLoginHandler.tsx:useLoginHandler():doLogin() contains the following logic:

const ent = generateBip39Entropy(key);
const hexKey = entropyToPrivateKey(ent);
LoginStore.loginWithPrivateKey(await pin(hexKey));

This references logic defined in the file src/branch/main/packages/app/src/Utils/nip6.ts (i.e., generateBip39Entropy(), entropyToPrivateKey()).

The primary concern is this logic in the function generateBip39Entropy() which uses the function bip39.mnemonicToEntropy() from the package @scure/bip39:

export function generateBip39Entropy(mnemonic?: string): Uint8Array {
  try {
    const mn = mnemonic ?? bip39.generateMnemonic(wordlist, 256);
    return bip39.mnemonicToEntropy(mn, wordlist);
  } catch (e) {
    throw new Error("INVALID MNEMONIC PHRASE");
  }
}

The login process should instead be using the the function await bip39.mnemonicToSeed() from the package @scure/bip39:

export async function generateBip39Seed(mnemonic?: string): Uint8Array {
  try {
    const mn = mnemonic ?? bip39.generateMnemonic(wordlist, 256);
    return await bip39.mnemonicToSeed(mn);
  } catch (e) {
    throw new Error("INVALID MNEMONIC PHRASE");
  }
}

For clarification, the current logic respects the following process:

  1. Generate entropy.
  2. Calculate mnemonic bytes as SHA256 of entropy and append a checksum, split into 11-bit integers for word list indices.
  3. Login with mnemonic.
  4. Generate entropy bytes from mnemonic. [INCORRECT]
  5. Calculate private key from entropy bytes. [INCORRECT]

Whereas, the logic should instead respect the following process:

  1. Generate entropy.
  2. Calculate mnemonic bytes as SHA256 of entropy and append a checksum, split into 11-bit integers for word list indices.
  3. Login with mnemonic.
  4. Calculate seed bytes from mnemonic. [CORRECT]
  5. Calculate private key from seed bytes. [CORRECT]

1 above: https://learnmeabitcoin.com/technical/mnemonic#generate-entropy
2 above: https://learnmeabitcoin.com/technical/mnemonic#entropy-to-mnemonic
4 & 5 [CORRECT] above: https://learnmeabitcoin.com/technical/mnemonic#mnemonic-to-seed

Additional context

This BIP-39 documentation does not mention recalculating entropy from the mnemonic:
https://bips.xyz/39#from-mnemonic-to-seed

I verified that the values from this suggested change match the values generated using the @scure/bip32 and @scure/bip39 typescript libraries:
https://github.com/paulmillr/scure-bip32
https://github.com/paulmillr/scure-bip39

import { HDKey } from "@scure/bip32";
import * as bip39 from "@scure/bip39";

const words = 'PUT PHRASE HERE';
const seed = await bip39.mnemonicToSeed(words);
const rootKey = HDKey.fromMasterSeed(seed);
const derivedKey = rootKey.derive("m/44'/1237'/0'/0/0");

I verified that the values from this suggested change match the values generated using the NBitcoin C# library:
https://github.com/MetacoSA/NBitcoin

var words = "PUT PHRASE HERE";
var seed = new NBitcoin.Mnemonic(words).DeriveSeed();
var rootKey = NBitcoin.ExtKey.CreateFromSeed(seed);
var derivedKey = rootKey.Derive(NBitcoin.KeyPath.Parse("m/44'/1237'/0'/0/0"));

I verified that the values from this suggested change match the Seed and BIP32 Root Key provided here using an identical phrase:
https://bitaps.com/mnemonic

**Description** The file `src/branch/main/packages/app/src/Hooks/useLoginHandler.tsx:useLoginHandler():doLogin()` contains the following logic: ```typescript const ent = generateBip39Entropy(key); const hexKey = entropyToPrivateKey(ent); LoginStore.loginWithPrivateKey(await pin(hexKey)); ``` This references logic defined in the file `src/branch/main/packages/app/src/Utils/nip6.ts` (i.e., `generateBip39Entropy()`, `entropyToPrivateKey()`). The primary concern is this logic in the function `generateBip39Entropy()` which uses the function `bip39.mnemonicToEntropy()` from the package `@scure/bip39`: ```typescript export function generateBip39Entropy(mnemonic?: string): Uint8Array { try { const mn = mnemonic ?? bip39.generateMnemonic(wordlist, 256); return bip39.mnemonicToEntropy(mn, wordlist); } catch (e) { throw new Error("INVALID MNEMONIC PHRASE"); } } ``` The login process should instead be using the the function `await bip39.mnemonicToSeed()` from the package `@scure/bip39`: ```typescript export async function generateBip39Seed(mnemonic?: string): Uint8Array { try { const mn = mnemonic ?? bip39.generateMnemonic(wordlist, 256); return await bip39.mnemonicToSeed(mn); } catch (e) { throw new Error("INVALID MNEMONIC PHRASE"); } } ``` For clarification, the current logic respects the following process: 1) Generate entropy. 2) Calculate mnemonic bytes as SHA256 of entropy and append a checksum, split into 11-bit integers for word list indices. 3) Login with mnemonic. 4) ___Generate entropy___ bytes from mnemonic. ___[INCORRECT]___ 5) Calculate private key from ___entropy___ bytes. ___[INCORRECT]___ Whereas, the logic should instead respect the following process: 1) Generate entropy. 2) Calculate mnemonic bytes as SHA256 of entropy and append a checksum, split into 11-bit integers for word list indices. 3) Login with mnemonic. 4) ___Calculate seed___ bytes from mnemonic. ___[CORRECT]___ 5) Calculate private key from ___seed___ bytes. ___[CORRECT]___ 1 above: https://learnmeabitcoin.com/technical/mnemonic#generate-entropy 2 above: https://learnmeabitcoin.com/technical/mnemonic#entropy-to-mnemonic 4 & 5 [CORRECT] above: https://learnmeabitcoin.com/technical/mnemonic#mnemonic-to-seed **Additional context** This BIP-39 documentation does not mention recalculating entropy from the mnemonic: https://bips.xyz/39#from-mnemonic-to-seed I verified that the values from this suggested change match the values generated using the `@scure/bip32` and `@scure/bip39` typescript libraries: https://github.com/paulmillr/scure-bip32 https://github.com/paulmillr/scure-bip39 ```typescript import { HDKey } from "@scure/bip32"; import * as bip39 from "@scure/bip39"; const words = 'PUT PHRASE HERE'; const seed = await bip39.mnemonicToSeed(words); const rootKey = HDKey.fromMasterSeed(seed); const derivedKey = rootKey.derive("m/44'/1237'/0'/0/0"); ``` I verified that the values from this suggested change match the values generated using the NBitcoin C# library: https://github.com/MetacoSA/NBitcoin ```csharp var words = "PUT PHRASE HERE"; var seed = new NBitcoin.Mnemonic(words).DeriveSeed(); var rootKey = NBitcoin.ExtKey.CreateFromSeed(seed); var derivedKey = rootKey.Derive(NBitcoin.KeyPath.Parse("m/44'/1237'/0'/0/0")); ``` I verified that the values from this suggested change match the `Seed` and `BIP32 Root Key` provided here using an identical phrase: https://bitaps.com/mnemonic
Kieran added the
bug
label 2024-01-31 09:57:43 +00:00
Kieran added the
P2
label 2024-05-27 14:50:37 +00:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: Kieran/snort#729
No description provided.