Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

metamask patch init #1

Merged
merged 8 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 33 additions & 12 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import { sha512 } from '@noble/hashes/sha512';
import { randomBytes } from '@noble/hashes/utils';
import { utils as baseUtils } from '@scure/base';

// Japanese wordlist
const isJapanese = (wordlist: string[]) => wordlist[0] === '\u3042\u3044\u3053\u304f\u3057\u3093';

// Normalization replaces equivalent sequences of characters
// so that any two texts that are equivalent will be reduced
// to the same sequence of code points, called the normal form of the original text.
Expand Down Expand Up @@ -36,7 +33,7 @@ function assertEntropy(entropy: Uint8Array) {
* generateMnemonic(wordlist, 128)
* // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
*/
export function generateMnemonic(wordlist: string[], strength: number = 128): string {
export function generateMnemonic(wordlist: string[], strength: number = 128): Uint8Array {
assert.number(strength);
if (strength % 32 !== 0 || strength > 256) throw new TypeError('Invalid entropy');
return entropyToMnemonic(randomBytes(strength / 8), wordlist);
Expand Down Expand Up @@ -76,9 +73,17 @@ function getCoder(wordlist: string[]) {
* 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
* ])
*/
export function mnemonicToEntropy(mnemonic: string, wordlist: string[]): Uint8Array {
const { words } = normalize(mnemonic);
const entropy = getCoder(wordlist).decode(words);
export function mnemonicToEntropy(mnemonic: string | Uint8Array, wordlist: string[]): Uint8Array {
let entropy;
if (typeof mnemonic === 'string') {
const { words } = normalize(mnemonic);
entropy = getCoder(wordlist).decode(words)
} else {
// expected intanceOf Uint8Array when used with eth-hd-keyring
entropy = getCoder(wordlist).decode(
Array.from(new Uint16Array(mnemonic.buffer)).map((i) => wordlist[i])
);
}
adonesky1 marked this conversation as resolved.
Show resolved Hide resolved
assertEntropy(entropy);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking much better now!

Thinking about it, maybe we should just number[] a.k.a. array of indexes instead of Uint8Array? It would become:

entropy = getCoder(wordlist).decode(mnemonic.map((i) => wordlist[i]));

Having number[] is even better: it clearly says "I am waiting for array of numbers". If we keep Uint8Array, that would mean "we are waiting for some buffer, which is not really a buffer, but an array of numbers".

Copy link
Author

@adonesky1 adonesky1 Sep 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for now we will keep Uint8Array for uniformity and flexibility and consider migrating all to number[] at some point.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, I will probably add the number[] to the main library and you won't need to maintain the fork when you'll decide to go number[] way.

return entropy;
}
Expand All @@ -96,16 +101,18 @@ export function mnemonicToEntropy(mnemonic: string, wordlist: string[]): Uint8Ar
* entropyToMnemonic(ent, wordlist);
* // 'legal winner thank year wave sausage worth useful legal winner thank yellow'
*/
export function entropyToMnemonic(entropy: Uint8Array, wordlist: string[]): string {
export function entropyToMnemonic(entropy: Uint8Array, wordlist: string[]): Uint8Array {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe keep the method as-is, and create a new one:

export function entropyToMnemonicIndexes(entropy: Uint8Array, wordlist: string[]): number[] {
  assertEntropy(entropy);
  const words = getCoder(wordlist).encode(entropy);
  return words.map((word) => wordlist.indexOf(word));
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure we can do this, though we won't be using the old one with this fork...

assertEntropy(entropy);
const words = getCoder(wordlist).encode(entropy);
return words.join(isJapanese(wordlist) ? '\u3000' : ' ');
const indices = words.map((word) => wordlist.indexOf(word));
const uInt8ArrayOfMnemonic = new Uint8Array(new Uint16Array(indices).buffer);
return uInt8ArrayOfMnemonic;
}

/**
* Validates mnemonic for being 12-24 words contained in `wordlist`.
*/
export function validateMnemonic(mnemonic: string, wordlist: string[]): boolean {
export function validateMnemonic(mnemonic: string | Uint8Array, wordlist: string[]): boolean {
try {
mnemonicToEntropy(mnemonic, wordlist);
} catch (e) {
Expand Down Expand Up @@ -140,6 +147,20 @@ export function mnemonicToSeed(mnemonic: string, passphrase = '') {
* mnemonicToSeedSync(mnem, 'password');
* // new Uint8Array([...64 bytes])
*/
export function mnemonicToSeedSync(mnemonic: string, passphrase = '') {
return pbkdf2(sha512, normalize(mnemonic).nfkd, salt(passphrase), { c: 2048, dkLen: 64 });
export function mnemonicToSeedSync(
mnemonic: string | Uint8Array,
wordlist: string[],
passphrase = ''
) {
let mnemonicUint8Array;
if (typeof mnemonic === 'string') {
mnemonicUint8Array = new TextEncoder().encode(normalize(mnemonic).nfkd);
} else {
mnemonicUint8Array = new TextEncoder().encode(
Array.from(new Uint16Array(mnemonic.buffer))
.map((i) => wordlist[i])
.join(' ')
);
}
return pbkdf2(sha512, mnemonicUint8Array, salt(passphrase), { c: 2048, dkLen: 64 });
}
Loading