Mnemonic Language Detection Utils
This commit is contained in:
@@ -1,9 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
bip39WordListEnglish,
|
|
||||||
decodeBip39MnemonicNonStandard,
|
decodeBip39MnemonicNonStandard,
|
||||||
deriveSeedFromBip39Mnemonic,
|
deriveSeedFromBip39Mnemonic,
|
||||||
encodeBip39MnemonicNonStandard,
|
encodeBip39MnemonicNonStandard,
|
||||||
generateBip39MnemonicNonStandard,
|
generateBip39MnemonicNonStandard,
|
||||||
|
// Word lists.
|
||||||
|
bip39WordListChineseSimplified,
|
||||||
|
bip39WordListChineseTraditional,
|
||||||
|
bip39WordListCzech,
|
||||||
|
bip39WordListEnglish,
|
||||||
|
bip39WordListFrench,
|
||||||
|
bip39WordListItalian,
|
||||||
|
bip39WordListJapanese,
|
||||||
|
bip39WordListKorean,
|
||||||
|
bip39WordListPortuguese,
|
||||||
|
bip39WordListSpanish,
|
||||||
} from '@bitauth/libauth';
|
} from '@bitauth/libauth';
|
||||||
import { Bytes } from './bytes.js';
|
import { Bytes } from './bytes.js';
|
||||||
|
|
||||||
@@ -253,15 +263,79 @@ export class Mnemonic {
|
|||||||
* Checks if a word exists in the provided dictionary.
|
* Checks if a word exists in the provided dictionary.
|
||||||
*
|
*
|
||||||
* @param word Word to check.
|
* @param word Word to check.
|
||||||
* @param dictionary Optional wordlist (defaults to English BIP-39 wordlist).
|
* @param wordList Optional wordlist (defaults to English BIP-39 wordlist).
|
||||||
*
|
*
|
||||||
* @returns boolean indicating if the word is valid.
|
* @returns boolean indicating if the word is valid.
|
||||||
*/
|
*/
|
||||||
public static isValidWord(
|
public static isValidWord(
|
||||||
word: string,
|
word: string,
|
||||||
dictionary: string[] = bip39WordListEnglish,
|
wordList: string[] = bip39WordListEnglish,
|
||||||
): boolean {
|
): boolean {
|
||||||
return dictionary.includes(word.toLowerCase());
|
return wordList.includes(word.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect which languages (word-lists) the given mnemonic matches.
|
||||||
|
*
|
||||||
|
* @param words The mnemonic words to check
|
||||||
|
* @param wordLists The BIP39 word lists to check against, keyed by language name
|
||||||
|
* @param allowPartialMatches If true, treats incomplete words as valid matches (useful for autocomplete)
|
||||||
|
*
|
||||||
|
* @returns Object mapping language names to their word lists for all matching languages
|
||||||
|
*/
|
||||||
|
public static detectLanguages(
|
||||||
|
words: Array<string>,
|
||||||
|
wordLists: { [name: string]: Array<string> },
|
||||||
|
allowPartialMatches = false,
|
||||||
|
): { [name: string]: Array<string> } {
|
||||||
|
// Define our match function.
|
||||||
|
const isWordMatch = (word: string, wordList: Array<string>): boolean => {
|
||||||
|
if (allowPartialMatches && word.length === 0) return true;
|
||||||
|
if (wordList.includes(word)) return true;
|
||||||
|
return (
|
||||||
|
allowPartialMatches &&
|
||||||
|
wordList.some((fullWord) => fullWord.startsWith(word))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Iterate over each word-list and check whether it's a match.
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(wordLists).filter(([, wordList]) =>
|
||||||
|
words.every((word) => isWordMatch(word, wordList)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all valid BIP39 words from languages that match the given mnemonic words.
|
||||||
|
*
|
||||||
|
* Uses partial matching to determine eligible languages, then returns all words
|
||||||
|
* from those languages (useful for autocomplete and word validation).
|
||||||
|
*
|
||||||
|
* @param words The mnemonic words to check (can be partial/incomplete)
|
||||||
|
* @param wordLists The BIP39 word lists to check against, keyed by language name
|
||||||
|
* @returns Array of all unique words from matching languages, sorted alphabetically
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* // Get all valid words for languages that match partial input
|
||||||
|
* const eligibleWords = Mnemonic.getEligibleWords(['aban', 'abil'], wordLists);
|
||||||
|
* // Returns all words from languages where 'aban*' and 'abil*' are valid prefixes
|
||||||
|
*
|
||||||
|
* // Filter for autocomplete
|
||||||
|
* const completions = eligibleWords.filter(word => word.startsWith('acc'));
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
public static getEligibleWords(
|
||||||
|
words: Array<string>,
|
||||||
|
wordLists: { [name: string]: Array<string> },
|
||||||
|
): Array<string> {
|
||||||
|
// Given the words provided, find eligible languages/word-lists.
|
||||||
|
const matchingLanguages = this.detectLanguages(words, wordLists, true);
|
||||||
|
|
||||||
|
// Merge all eligible word completions into an Array.
|
||||||
|
// NOTE: We use a Set to de-deuplicate words that might appear in multiple word-lists.
|
||||||
|
return [...new Set<string>(Object.values(matchingLanguages).flat())];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -347,3 +421,24 @@ export class Mnemonic {
|
|||||||
return this.mnemonic.passphrase;
|
return this.mnemonic.passphrase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: This is handled exceptionally due to tree-shaking considerations.
|
||||||
|
// Word lists incur a large cost on the bundle size and LibAuth considers non-English word-lists as non-standard:
|
||||||
|
// https://github.com/bitauth/libauth/blob/master/src/lib/key/bip39.ts#L178
|
||||||
|
// And the BIP39 spec warns against their usage:
|
||||||
|
// https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#wordlists
|
||||||
|
// If we include this in the class, it cannot be tree-shaken by most tooling, so we define a stand-alone function instead.
|
||||||
|
export function getAllBIP39WordLists() {
|
||||||
|
return {
|
||||||
|
'Chinese Simplified': bip39WordListChineseSimplified,
|
||||||
|
'Chinese Traditional': bip39WordListChineseTraditional,
|
||||||
|
Czech: bip39WordListCzech,
|
||||||
|
English: bip39WordListEnglish,
|
||||||
|
French: bip39WordListFrench,
|
||||||
|
Italian: bip39WordListItalian,
|
||||||
|
Japanese: bip39WordListJapanese,
|
||||||
|
Korean: bip39WordListKorean,
|
||||||
|
Portuguese: bip39WordListPortuguese,
|
||||||
|
Spanish: bip39WordListSpanish,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user