Merge branch 'fix_passphrase_seed' into 'development'

Fix passphrase seed generation and use LibAuth vectors

See merge request GeneralProtocols/xo/stack!102
This commit is contained in:
Jim Hamill
2025-06-23 11:47:48 +00:00
2 changed files with 117 additions and 108 deletions
+3 -1
View File
@@ -270,7 +270,9 @@ export class Mnemonic {
* @returns The seed (for use with HDPrivateNodes). * @returns The seed (for use with HDPrivateNodes).
*/ */
public toSeed(): Uint8Array { public toSeed(): Uint8Array {
return deriveSeedFromBip39Mnemonic(this.toPhrase()); return deriveSeedFromBip39Mnemonic(this.toPhrase(false), {
passphrase: this.getPassphrase(),
});
} }
/** /**
+114 -107
View File
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest'; import { describe, it, expect } from 'vitest';
import { Bytes } from '~/src/bytes'; import { Bytes } from '../src/bytes';
import { Mnemonic, MnemonicRaw } from '~/src/mnemonic'; import { Mnemonic, MnemonicRaw } from '../src/mnemonic';
describe('Success cases', () => { describe('Success cases', () => {
// Simple array of cases // Simple array of cases
@@ -9,6 +9,7 @@ describe('Success cases', () => {
fromWords: Array<string>; fromWords: Array<string>;
passphrase?: string; passphrase?: string;
raw: MnemonicRaw; raw: MnemonicRaw;
toEntropy: Uint8Array;
toSeed: Uint8Array; toSeed: Uint8Array;
toPhrase: string; toPhrase: string;
toPhraseWithoutPassphrase: string; toPhraseWithoutPassphrase: string;
@@ -18,145 +19,151 @@ describe('Success cases', () => {
// No pass-phrase // No pass-phrase
{ {
fromPhrase: fromPhrase:
'goose just fan kidney barrel album wave crowd movie flame cousin exhaust', 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
fromWords: [ fromWords: [
'goose', 'abandon',
'just', 'abandon',
'fan', 'abandon',
'kidney', 'abandon',
'barrel', 'abandon',
'album', 'abandon',
'wave', 'abandon',
'crowd', 'abandon',
'movie', 'abandon',
'flame', 'abandon',
'cousin', 'abandon',
'exhaust', 'about',
], ],
raw: { raw: {
words: [ words: [
'goose', 'abandon',
'just', 'abandon',
'fan', 'abandon',
'kidney', 'abandon',
'barrel', 'abandon',
'album', 'abandon',
'wave', 'abandon',
'crowd', 'abandon',
'movie', 'abandon',
'flame', 'abandon',
'cousin', 'abandon',
'exhaust', 'about',
], ],
}, },
toEntropy: Bytes.fromHex(
'00000000000000000000000000000000',
).toUint8Array(),
toSeed: Bytes.fromHex( toSeed: Bytes.fromHex(
'7066f43a742829f0edce7d8e3c31651df320f13913995a6500f4e515db372b35202227f923ff181defc35cea02f8468df39f8fa9d97a202d252e61562e4bbfb5', '5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4',
).toUint8Array(), ).toUint8Array(),
toPhrase: toPhrase:
'goose just fan kidney barrel album wave crowd movie flame cousin exhaust', 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
toPhraseWithoutPassphrase: toPhraseWithoutPassphrase:
'goose just fan kidney barrel album wave crowd movie flame cousin exhaust', 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
toWords: [ toWords: [
'goose', 'abandon',
'just', 'abandon',
'fan', 'abandon',
'kidney', 'abandon',
'barrel', 'abandon',
'album', 'abandon',
'wave', 'abandon',
'crowd', 'abandon',
'movie', 'abandon',
'flame', 'abandon',
'cousin', 'abandon',
'exhaust', 'about',
], ],
toWordsWithoutPassphrase: [ toWordsWithoutPassphrase: [
'goose', 'abandon',
'just', 'abandon',
'fan', 'abandon',
'kidney', 'abandon',
'barrel', 'abandon',
'album', 'abandon',
'wave', 'abandon',
'crowd', 'abandon',
'movie', 'abandon',
'flame', 'abandon',
'cousin', 'abandon',
'exhaust', 'about',
], ],
}, },
// Passphrase // Passphrase
{ {
fromPhrase: fromPhrase:
'goose just fan kidney barrel album wave crowd movie flame cousin exhaust GeneralProtocols!', 'legal winner thank year wave sausage worth useful legal winner thank yellow Libauth',
fromWords: [ fromWords: [
'goose', 'legal',
'just', 'winner',
'fan', 'thank',
'kidney', 'year',
'barrel',
'album',
'wave', 'wave',
'crowd', 'sausage',
'movie', 'worth',
'flame', 'useful',
'cousin', 'legal',
'exhaust', 'winner',
'GeneralProtocols!', 'thank',
'yellow',
'Libauth',
], ],
passphrase: 'GeneralProtocols!', passphrase: 'Libauth',
raw: { raw: {
words: [ words: [
'goose', 'legal',
'just', 'winner',
'fan', 'thank',
'kidney', 'year',
'barrel',
'album',
'wave', 'wave',
'crowd', 'sausage',
'movie', 'worth',
'flame', 'useful',
'cousin', 'legal',
'exhaust', 'winner',
'thank',
'yellow',
], ],
passphrase: 'GeneralProtocols!', passphrase: 'Libauth',
}, },
toEntropy: Bytes.fromHex(
'7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f',
).toUint8Array(),
toSeed: Bytes.fromHex( toSeed: Bytes.fromHex(
'2f706756ab2083f7ce07c0c0fcde8f14f062da5de839f42763262b25e0d871f03dd2b561d55eaacc471c94da656ee7b0007fb48a64e31ec91a1a2ba706b46b89', '0199495e71f9e7f40b52febf82dcb1a6c342e9178a5e8cfea4204cf6b2071e89345ab83e8a5f0ea3ae59025e5e2e8dd2c965752541912f28ead8a33ff7dd11dd',
).toUint8Array(), ).toUint8Array(),
toPhrase: toPhrase:
'goose just fan kidney barrel album wave crowd movie flame cousin exhaust GeneralProtocols!', 'legal winner thank year wave sausage worth useful legal winner thank yellow Libauth',
toPhraseWithoutPassphrase: toPhraseWithoutPassphrase:
'goose just fan kidney barrel album wave crowd movie flame cousin exhaust', 'legal winner thank year wave sausage worth useful legal winner thank yellow',
toWords: [ toWords: [
'goose', 'legal',
'just', 'winner',
'fan', 'thank',
'kidney', 'year',
'barrel',
'album',
'wave', 'wave',
'crowd', 'sausage',
'movie', 'worth',
'flame', 'useful',
'cousin', 'legal',
'exhaust', 'winner',
'GeneralProtocols!', 'thank',
'yellow',
'Libauth',
], ],
toWordsWithoutPassphrase: [ toWordsWithoutPassphrase: [
'goose', 'legal',
'just', 'winner',
'fan', 'thank',
'kidney', 'year',
'barrel',
'album',
'wave', 'wave',
'crowd', 'sausage',
'movie', 'worth',
'flame', 'useful',
'cousin', 'legal',
'exhaust', 'winner',
'thank',
'yellow',
], ],
}, },
]; ];
@@ -211,7 +218,7 @@ describe('Success cases', () => {
it.each(testCases)( it.each(testCases)(
'toWords(withoutPassphrase)', 'toWords(withoutPassphrase)',
({ toWordsWithoutPassphrase, passphrase, raw }) => { ({ toWordsWithoutPassphrase, _passphrase, raw }) => {
const mnemonic = Mnemonic.fromRaw(raw); const mnemonic = Mnemonic.fromRaw(raw);
expect(mnemonic.toWords(false)).toStrictEqual(toWordsWithoutPassphrase); expect(mnemonic.toWords(false)).toStrictEqual(toWordsWithoutPassphrase);
}, },