Added lazy instantiation to wordlists.
This commit is contained in:
parent
f24aa17709
commit
7dd9049993
@ -1,5 +1,8 @@
|
||||
const Base64 = ")!@#$%^&*(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_";
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export function decodeBits(width: number, data: string): Array<number> {
|
||||
const maxValue = (1 << width) - 1;
|
||||
const result: Array<number> = [ ];
|
||||
|
@ -19,6 +19,9 @@ function unfold(words: Array<string>, sep: string): Array<string> {
|
||||
}, <Array<string>>[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export function decode(data: string, subs: string): Array<string> {
|
||||
|
||||
// Replace all the substitutions with their expanded form
|
||||
@ -43,6 +46,9 @@ export function decode(data: string, subs: string): Array<string> {
|
||||
return unfold(unfold(clumps, ";"), ":");
|
||||
}
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export function decodeOwl(data: string): Array<string> {
|
||||
assertArgument(data[0] === "0", "unsupported auwl data", "data", data);
|
||||
|
||||
|
@ -3,6 +3,9 @@ import { assertArgument } from "../utils/index.js";
|
||||
import { decodeBits } from "./bit-reader.js";
|
||||
import { decodeOwl } from "./decode-owl.js";
|
||||
|
||||
/**
|
||||
* @_ignore
|
||||
*/
|
||||
export function decodeOwlA(data: string, accents: string): Array<string> {
|
||||
let words = decodeOwl(data).join(",");
|
||||
|
||||
|
@ -1,7 +1,24 @@
|
||||
|
||||
/**
|
||||
* A Wordlist is a set of 2048 words used to encode private keys
|
||||
* (or other binary data) that is easier for humans to write down,
|
||||
* transcribe and dictate.
|
||||
*
|
||||
* The [[link-bip-39]] standard includes several checksum bits,
|
||||
* depending on the size of the mnemonic phrase.
|
||||
*
|
||||
* A mnemonic phrase may be 12, 15, 18, 21 or 24 words long. For
|
||||
* most purposes 12 word mnemonics should be used, as including
|
||||
* additional words increases the difficulty and potential for
|
||||
* mistakes and does not offer any effective improvement on security.
|
||||
*
|
||||
* There are a variety of [[link-bip39-wordlists]] for different
|
||||
* languages, but for maximal compatibility, the
|
||||
* [English Wordlist](LangEn) is recommended.
|
||||
*
|
||||
* @_section: api/wordlists:Wordlists [wordlists]
|
||||
*/
|
||||
export { Wordlist } from "./wordlist.js";
|
||||
export { langEn, LangEn } from "./lang-en.js";
|
||||
export { wordlists } from "./wordlists.js";
|
||||
export { LangEn } from "./lang-en.js";
|
||||
|
||||
export { WordlistOwl } from "./wordlist-owl.js";
|
||||
export { WordlistOwlA } from "./wordlist-owla.js";
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -4,8 +4,30 @@ const words = "0arertoiotadonoaRteirroenaNonaLsolocoiliaralaorrenadaChoN$n0A>Dom
|
||||
const accents = "aeiou7695@@BZWWavwUJkO@Y-Kn))YEGq#E@O)cI@#ZkMHv$e*))M!!)D**$GW!oKm*Acoh^k&It-pi^SYW)$^n!G)bO!Wkzam(jS#X)Og*^l^RW!bQ#QygBKXfzE))hti!Qm)Cng%%c)mJiI*HJWbmYniCLwNdYyY%WKO^bnT$PuGOr!IvHu&G(GKbtBuhiW&!eO@XMeoYQeCa#!MrTJCq!OW&CHG(WCcW%%)$rfrIegu$)w!G)JGmWWw)MnD%SXXWIT^LWAZuVWB^W)eTL^x&$WGHW(nKWEMA)#$F$x$Waekqs,n7715)W*HM-$WAcCiu(a))VCZ)GG%(*CWWdW%$D!UCO$M";
|
||||
const checksum = "0xf74fb7092aeacdfbf8959557de22098da512207fb9f109cb526994938cf40300";
|
||||
|
||||
let wordlist: null | LangEs = null;
|
||||
|
||||
/**
|
||||
* The [[link-bip-39]] Wordlist for the Spanish (es) language.
|
||||
*
|
||||
* @_docloc: api/wordlists
|
||||
*/
|
||||
export class LangEs extends WordlistOwlA {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Spanish language Wordlist.
|
||||
*
|
||||
* This should be unnecessary most of the time as the exported
|
||||
* [[langEs]] should suffice.
|
||||
*/
|
||||
constructor() { super("es", words, accents, checksum); }
|
||||
|
||||
/**
|
||||
* Returns a singleton instance of a ``LangEs``, creating it
|
||||
* if this is the first time being called.
|
||||
*/
|
||||
static wordlist(): LangEs {
|
||||
if (wordlist == null) { wordlist = new LangEs(); }
|
||||
return wordlist;
|
||||
}
|
||||
}
|
||||
|
||||
export const langEs = new LangEs();
|
||||
|
@ -4,8 +4,29 @@ const words = "0erreleontiteurinueiriet cegeanseali medenel q)eniluxaus ch0Ais}A
|
||||
const accents = "e7693&)U*o&)Ry^)*)W))))#X^))))@@)#Wf)m%)#!))AG)&IIAQIIIBIIHJNAgBIILIDJGo)))HIQIIIIA(IGgJHH(BIIxX#)Ou)@*IAAPIIIJHQJ)&QIQPYI(HYAQC%)!))QHJJ@)#)^f*^AXCJ))$%CP))%&m)u)@e^A#G#))W@!(IKK%!(I%))O@QA))@GG#e))))WHJIWh))my@IIBT^)!)HAYGETHI*))!QnUDG)))nBoKAC*HwyQh))$&)G&)UGO)G)))(BX#v**)%O,e7686)I))@)&)gdMP()))ud)p#L))I^FIHYdWG))D@DFV)QA)o%MyTh%*)Z)%)n(XANc^R)YS";
|
||||
const checksum = "0x51deb7ae009149dc61a6bd18a918eb7ac78d2775726c68e598b92d002519b045";
|
||||
|
||||
export class LangFr extends WordlistOwlA {
|
||||
constructor() { super("fr", words, accents, checksum); }
|
||||
}
|
||||
let wordlist: null | LangFr = null;
|
||||
|
||||
export const langFr = new LangFr();
|
||||
/**
|
||||
* The [[link-bip-39]] Wordlist for the French (fr) language.
|
||||
*
|
||||
* @_docloc: api/wordlists
|
||||
*/
|
||||
export class LangFr extends WordlistOwlA {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the French language Wordlist.
|
||||
*
|
||||
* This should be unnecessary most of the time as the exported
|
||||
* [[langFr]] should suffice.
|
||||
*/
|
||||
constructor() { super("fr", words, accents, checksum); }
|
||||
|
||||
/**
|
||||
* Returns a singleton instance of a ``LangFr``, creating it
|
||||
* if this is the first time being called.
|
||||
*/
|
||||
static wordlist(): LangFr {
|
||||
if (wordlist == null) { wordlist = new LangFr(); }
|
||||
return wordlist;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -35,7 +35,7 @@ const mapping = "~~AzB~X~a~KN~Q~D~S~C~G~E~Y~p~L~I~O~eH~g~V~hxyumi~~U~~Z~~v~~s~~d
|
||||
|
||||
let _wordlist: null | Array<string> = null;
|
||||
|
||||
function hex(word: string) {
|
||||
function hex(word: string): string {
|
||||
return hexlify(toUtf8Bytes(word));
|
||||
}
|
||||
|
||||
@ -131,7 +131,21 @@ function loadWords(): Array<string> {
|
||||
return wordlist;
|
||||
}
|
||||
|
||||
class LangJa extends Wordlist {
|
||||
let wordlist: null | LangJa = null;
|
||||
|
||||
/**
|
||||
* The [[link-bip-39]] Wordlist for the Japanese (ja) language.
|
||||
*
|
||||
* @_docloc: api/wordlists
|
||||
*/
|
||||
export class LangJa extends Wordlist {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Japanese language Wordlist.
|
||||
*
|
||||
* This should be unnecessary most of the time as the exported
|
||||
* [[langJa]] should suffice.
|
||||
*/
|
||||
constructor() { super("ja"); }
|
||||
|
||||
getWord(index: number): string {
|
||||
@ -145,14 +159,21 @@ class LangJa extends Wordlist {
|
||||
return loadWords().indexOf(word);
|
||||
}
|
||||
|
||||
split(mnemonic: string): Array<string> {
|
||||
split(phrase: string): Array<string> {
|
||||
//logger.assertNormalize();
|
||||
return mnemonic.split(/(?:\u3000| )+/g);
|
||||
return phrase.split(/(?:\u3000| )+/g);
|
||||
}
|
||||
|
||||
join(words: Array<string>): string {
|
||||
return words.join("\u3000");
|
||||
}
|
||||
}
|
||||
|
||||
export const langJa = new LangJa();
|
||||
/**
|
||||
* Returns a singleton instance of a ``LangJa``, creating it
|
||||
* if this is the first time being called.
|
||||
*/
|
||||
static wordlist(): LangJa {
|
||||
if (wordlist == null) { wordlist = new LangJa(); }
|
||||
return wordlist;
|
||||
}
|
||||
}
|
||||
|
@ -61,8 +61,21 @@ function loadWords(): Array<string> {
|
||||
return wordlist;
|
||||
}
|
||||
|
||||
let wordlist: null | LangKo = null;
|
||||
|
||||
class LangKo extends Wordlist {
|
||||
/**
|
||||
* The [[link-bip-39]] Wordlist for the Korean (ko) language.
|
||||
*
|
||||
* @_docloc: api/wordlists
|
||||
*/
|
||||
export class LangKo extends Wordlist {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Korean language Wordlist.
|
||||
*
|
||||
* This should be unnecessary most of the time as the exported
|
||||
* [[langKo]] should suffice.
|
||||
*/
|
||||
constructor() {
|
||||
super("ko");
|
||||
}
|
||||
@ -77,6 +90,13 @@ class LangKo extends Wordlist {
|
||||
getWordIndex(word: string): number {
|
||||
return loadWords().indexOf(word);
|
||||
}
|
||||
}
|
||||
|
||||
export const langKo = new LangKo();
|
||||
/**
|
||||
* Returns a singleton instance of a ``LangKo``, creating it
|
||||
* if this is the first time being called.
|
||||
*/
|
||||
static wordlist(): LangKo {
|
||||
if (wordlist == null) { wordlist = new LangKo(); }
|
||||
return wordlist;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -58,8 +58,31 @@ function loadWords(locale: string): Array<string> {
|
||||
return wordlist;
|
||||
}
|
||||
|
||||
class LangZh extends Wordlist {
|
||||
constructor(country: string) { super("zh_" + country); }
|
||||
const wordlists: Record<string, LangZh> = { };
|
||||
|
||||
/**
|
||||
* The [[link-bip-39]] Wordlist for the Chinese language.
|
||||
*
|
||||
* This Wordlist supports both simplified and traditional
|
||||
* character set, depending on which is specified in the
|
||||
* constructor.
|
||||
*
|
||||
* For the ``zh_cn`` language use ``"cn"`` and for the ``zh_tw``
|
||||
* langauge, use ``"tw"``.
|
||||
*
|
||||
* @_docloc: api/wordlists
|
||||
*/
|
||||
export class LangZh extends Wordlist {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Chinese language Wordlist for
|
||||
* the %%dialect%%, either ``"cn"`` or ``"tw"`` for simplified
|
||||
* or traditional, respectively.
|
||||
*
|
||||
* This should be unnecessary most of the time as the exported
|
||||
* [[langZhCn]] and [[langZhTw]] should suffice.
|
||||
*/
|
||||
constructor(dialect: string) { super("zh_" + dialect); }
|
||||
|
||||
getWord(index: number): string {
|
||||
const words = loadWords(this.locale);
|
||||
@ -72,11 +95,19 @@ class LangZh extends Wordlist {
|
||||
return loadWords(this.locale).indexOf(word);
|
||||
}
|
||||
|
||||
split(mnemonic: string): Array<string> {
|
||||
mnemonic = mnemonic.replace(/(?:\u3000| )+/g, "");
|
||||
return mnemonic.split("");
|
||||
split(phrase: string): Array<string> {
|
||||
phrase = phrase.replace(/(?:\u3000| )+/g, "");
|
||||
return phrase.split("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a singleton instance of a ``LangZh`` for %%dialect%%,
|
||||
* creating it if this is the first time being called.
|
||||
*/
|
||||
static wordlist(dialect: string): LangZh {
|
||||
if (wordlists[dialect] == null) {
|
||||
wordlists[dialect] = new LangZh(dialect);
|
||||
}
|
||||
return wordlists[dialect];
|
||||
}
|
||||
}
|
||||
|
||||
export const langZhCn = new LangZh("cn");
|
||||
export const langZhTw = new LangZh("tw");
|
||||
|
@ -8,10 +8,26 @@ import { assertArgument } from "../utils/index.js";
|
||||
import { decodeOwl } from "./decode-owl.js";
|
||||
import { Wordlist } from "./wordlist.js";
|
||||
|
||||
/**
|
||||
* An OWL format Wordlist is an encoding method that exploits
|
||||
* the general locality of alphabetically sorted words to
|
||||
* achieve a simple but effective means of compression.
|
||||
*
|
||||
* This class is generally not useful to most developers as
|
||||
* it is used mainly internally to keep Wordlists for languages
|
||||
* based on ASCII-7 small.
|
||||
*
|
||||
* If necessary, there are tools within the ``generation/`` folder
|
||||
* to create these necessary data.
|
||||
*/
|
||||
export class WordlistOwl extends Wordlist {
|
||||
#data: string;
|
||||
#checksum: string;
|
||||
|
||||
/**
|
||||
* Creates a new Wordlist for %%locale%% using the OWL %%data%%
|
||||
* and validated against the %%checksum%%.
|
||||
*/
|
||||
constructor(locale: string, data: string, checksum: string) {
|
||||
super(locale);
|
||||
this.#data = data;
|
||||
|
@ -2,6 +2,18 @@
|
||||
import { WordlistOwl } from "./wordlist-owl.js";
|
||||
import { decodeOwlA } from "./decode-owla.js";
|
||||
|
||||
/**
|
||||
* An OWL-A format Wordlist extends the OWL format to add an
|
||||
* overlay onto an OWL format Wordlist to support diacritic
|
||||
* marks.
|
||||
*
|
||||
* This class is generally not useful to most developers as
|
||||
* it is used mainly internally to keep Wordlists for languages
|
||||
* based on latin-1 small.
|
||||
*
|
||||
* If necessary, there are tools within the ``generation/`` folder
|
||||
* to create these necessary data.
|
||||
*/
|
||||
export class WordlistOwlA extends WordlistOwl {
|
||||
#accent: string;
|
||||
|
||||
|
@ -1,22 +1,59 @@
|
||||
import { defineProperties } from "../utils/index.js";
|
||||
|
||||
/**
|
||||
* A Wordlist represents a collection of language-specific
|
||||
* words used to encode and devoce [[BIP-39]] encoded data
|
||||
* by mapping words to 11-bit values and vice versa.
|
||||
*/
|
||||
export abstract class Wordlist {
|
||||
locale!: string;
|
||||
|
||||
/**
|
||||
* Creates a new Wordlist instance.
|
||||
*
|
||||
* Sub-classes MUST call this if they provide their own constructor,
|
||||
* passing in the locale string of the language.
|
||||
*
|
||||
* Generally there is no need to create instances of a Wordlist,
|
||||
* since each language-specific Wordlist creates an instance and
|
||||
* there is no state kept internally, so they are safe to share.
|
||||
*/
|
||||
constructor(locale: string) {
|
||||
defineProperties<Wordlist>(this, { locale });
|
||||
}
|
||||
|
||||
// Subclasses may override this
|
||||
split(mnemonic: string): Array<string> {
|
||||
return mnemonic.toLowerCase().split(/ +/g)
|
||||
/**
|
||||
* Sub-classes may override this to provide a language-specific
|
||||
* method for spliting %%phrase%% into individual words.
|
||||
*
|
||||
* By default, %%phrase%% is split using any sequences of
|
||||
* white-space as defined by regular expressions (i.e. ``/\s+/``).
|
||||
*/
|
||||
split(phrase: string): Array<string> {
|
||||
return phrase.toLowerCase().split(/\s+/g)
|
||||
}
|
||||
|
||||
// Subclasses may override this
|
||||
/**
|
||||
* Sub-classes may override this to provider a language-specific
|
||||
* method for joining %%words%% into a phrase.
|
||||
*
|
||||
* By default, %%words%% are joined by a single space.
|
||||
*/
|
||||
join(words: Array<string>): string {
|
||||
return words.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps an 11-bit value into its coresponding word in the list.
|
||||
*
|
||||
* Sub-classes MUST override this.
|
||||
*/
|
||||
abstract getWord(index: number): string;
|
||||
|
||||
/**
|
||||
* Maps a word to its corresponding 11-bit value.
|
||||
*
|
||||
* Sub-classes MUST override this.
|
||||
*/
|
||||
abstract getWordIndex(word: string): number;
|
||||
}
|
||||
|
@ -1,15 +1,9 @@
|
||||
|
||||
import { langCz as cz } from "./lang-cz.js";
|
||||
import { langEs as es } from "./lang-es.js";
|
||||
import { langFr as fr } from "./lang-fr.js";
|
||||
import { langJa as ja } from "./lang-ja.js";
|
||||
import { langKo as ko } from "./lang-ko.js";
|
||||
import { langIt as it } from "./lang-it.js";
|
||||
import { langPt as pt } from "./lang-pt.js";
|
||||
import { langZhCn as zh_cn, langZhTw as zh_tw } from "./lang-zh.js";
|
||||
|
||||
import type { Wordlist } from "./wordlist.js";
|
||||
|
||||
export const wordlists: Record<string, Wordlist> = Object.freeze({
|
||||
cz, es, fr, ja, ko, it, pt, zh_cn, zh_tw
|
||||
});
|
||||
export { LangCz } from "./lang-cz.js";
|
||||
export { LangEs } from "./lang-es.js";
|
||||
export { LangFr } from "./lang-fr.js";
|
||||
export { LangJa } from "./lang-ja.js";
|
||||
export { LangKo } from "./lang-ko.js";
|
||||
export { LangIt } from "./lang-it.js";
|
||||
export { LangPt } from "./lang-pt.js";
|
||||
export { LangZh } from "./lang-zh.js";
|
||||
|
Loading…
Reference in New Issue
Block a user