diff --git a/src/index.js b/src/index.js index 373e5f2..41cbd4a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,19 +1,24 @@ const crypto = require('crypto'); const bip39 = require('bip39'); -const PREFIX = [0xC2, 0xFE, 0x58]; +const PREFIX = Buffer.from('C2FE58', 'hex'); const P2PKH = 0x00; const P2WPKHP2SH = 0x01; const P2WPKH = 0x02; +const getMnemonicBuffer = mnemonic => Buffer.from( + bip39.mnemonicToEntropy(mnemonic), + 'hex' +); + const bip39v = { versions: {P2PKH, P2WPKHP2SH, P2WPKH} }; bip39v.generateMnemonic = (length = 224, versionByte = P2PKH) => { const buffer = Buffer.concat([ - Buffer.from(PREFIX), + PREFIX, Buffer.from([versionByte]), crypto.randomBytes(length / 8) ]); @@ -21,11 +26,18 @@ bip39v.generateMnemonic = (length = 224, versionByte = P2PKH) => { return bip39.entropyToMnemonic(buffer); }; +bip39v.isVersionedMnemonic = mnemonic => { + const buffer = getMnemonicBuffer(mnemonic); + + return buffer.slice(0, PREFIX.length).equals(PREFIX); +}; + bip39v.mnemonicToVersionByte = mnemonic => { - const buffer = Buffer.from( - bip39.mnemonicToEntropy(mnemonic), - 'hex' - ); + if (!bip39v.isVersionedMnemonic(mnemonic)) { + throw new Error('Cannot get version byte of non-versioned mnemonic.'); + } + + const buffer = getMnemonicBuffer(mnemonic); return buffer[PREFIX.length]; }; diff --git a/test/unit.js b/test/unit.js index b2de20b..46d49af 100644 --- a/test/unit.js +++ b/test/unit.js @@ -11,8 +11,9 @@ const fixtures = { P2PKH: 'seed version abandon bus rebuild logic connect wise illegal traffic transfer olympic royal style equal', P2WPKHP2SH: 'seed version about math twice crater force critic grace panic party label flag draft sketch', P2WPKH: 'seed version absent reward pipe sketch clarify sight spread addict divorce idle burst alarm tide', - UNKNOWN: 'such galaxy much glimpse music turkey toward exhaust filter key pilot hello' - } + UNKNOWN: 'seed version divide rural field error snack clump gather shift globe mask trend october ten' + }, + nonVersionedMnemonic: 'much bottom such hurt hunt welcome cushion erosion pulse admit name deer' }; test('bip39v is exported', t => { @@ -48,10 +49,19 @@ test('bip39v.generateMnemonic(length, version) adds correct version', t => { }); }); +test('bip39v.isVersionedMnemonic(mnemonic) against fixture data', t => { + Object.values(fixtures.mnemonics).forEach(mnemonic => { + const isVersionedMnemonic = bip39v.isVersionedMnemonic(mnemonic); + t.true(isVersionedMnemonic); + }); + const isVersionedMnemonic = bip39v.isVersionedMnemonic(fixtures.nonVersionedMnemonic); + t.false(isVersionedMnemonic); +}); + test('bip39v.mnemonicToVersionByte(mnemonic) against fixture data', t => { Object.entries(fixtures.mnemonics).forEach(([version, mnemonic]) => { const versionByte = bip39v.mnemonicToVersionByte(mnemonic); - const expectedVersionByte = version === 'UNKNOWN' ? 0x44 : fixtures.versionBytes[version]; + const expectedVersionByte = version === 'UNKNOWN' ? 0xFF : fixtures.versionBytes[version]; t.is(versionByte, expectedVersionByte); }); });