Skip to content

Commit

Permalink
[crypto] allow mnemonics to be created with 12 or 24 words (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
allenan authored Oct 15, 2021
1 parent d0602be commit 16c6887
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 16 deletions.
11 changes: 9 additions & 2 deletions packages/crypto-react-native/src/Mnemonic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ import {
} from './utils'
import wordlist from './wordlists/english.json'

export type MnemonicLength = 12 | 24
export default class Mnemonic {
public words!: Array<string>

constructor(words: Array<string>) {
this.words = words
}

static async create(): Promise<Mnemonic> {
const entropy = await randomBytes(16)
static async create(length: MnemonicLength = 12): Promise<Mnemonic> {
if (![12, 24].includes(length)) {
throw new Error(`supported mnemonic lengths: 12, 24. received ${length}`)
}

const entropyBytes = (16 / 12) * length

const entropy = await randomBytes(entropyBytes)
return Mnemonic.fromEntropy(entropy)
}

Expand Down
16 changes: 13 additions & 3 deletions packages/crypto/src/Mnemonic.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {
lpad, deriveChecksumBits, binaryToByte, bytesToBinary,
} from './utils'
import { lpad, deriveChecksumBits, binaryToByte, bytesToBinary, randomBytes } from './utils'
import wordlist from './wordlists/english.json'

export type MnemonicLength = 12 | 24

export default class Mnemonic {
public words!: Array<string>
Expand All @@ -11,6 +10,17 @@ export default class Mnemonic {
this.words = words
}

static async create(length: MnemonicLength = 12): Promise<Mnemonic> {
if (![12, 24].includes(length)) {
throw new Error(`supported mnemonic lengths: 12, 24. received ${length}`)
}

const entropyBytes = (16 / 12) * length

const entropy = await randomBytes(entropyBytes)
return Mnemonic.fromEntropy(entropy)
}

static fromEntropy(entropy: Buffer): Mnemonic {
if (entropy.length < 16) throw new Error('invalid entropy, less than 16')
if (entropy.length > 32) throw new Error('invalid entropy, greater than 32')
Expand Down
39 changes: 28 additions & 11 deletions packages/crypto/src/__tests__/Mnemonic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,32 @@ import { Mnemonic } from '..'
import { randomBytes } from '../utils'
import { bobWords } from '../../../../integration_tests/fixtures/users'


describe('Mnemonic', () => {
it('is initialized with a list of words', () => {
const mnemonic = new Mnemonic(bobWords)
expect(mnemonic.words).toEqual(bobWords)
})
})

describe('create', () => {
it('creates a new mnemonic with 12 words by default', async () => {
const mnemonic = await Mnemonic.create()
expect(mnemonic.words.length).toBe(12)
})

it('can create a new mnemonic with 24 words', async () => {
const mnemonic = await Mnemonic.create(24)
expect(mnemonic.words.length).toBe(24)
})

it('raises an error if given a value besides 12 or 24', () => {
const expectedError = new Error('supported mnemonic lengths: 12, 24. received 36')
Mnemonic.create(36).catch((error) => {
expect(error).toEqual(expectedError)
})
})
})

describe('fromEntropy', () => {
it('creates a new mnemonic from given entropy', async () => {
const entropy = await randomBytes(16)
Expand All @@ -18,17 +36,17 @@ describe('fromEntropy', () => {
})

it('creates a new 24-word mnemonic from given entropy', async () => {
const entropy = await randomBytes(32)
const mnemonic = Mnemonic.fromEntropy(entropy)
expect(mnemonic.words.length).toBe(24)
})
const entropy = await randomBytes(32)
const mnemonic = Mnemonic.fromEntropy(entropy)
expect(mnemonic.words.length).toBe(24)
})

it('should generate bip39 checksum word', async () => {
// https://github.com/bitcoinjs/bip39/blob/master/test/vectors.json
const entropy = Buffer.from('00000000000000000000000000000000', 'hex')
const mnemonic = Mnemonic.fromEntropy(entropy)
expect(mnemonic.words[11]).toBe('about')
})
// https://github.com/bitcoinjs/bip39/blob/master/test/vectors.json
const entropy = Buffer.from('00000000000000000000000000000000', 'hex')
const mnemonic = Mnemonic.fromEntropy(entropy)
expect(mnemonic.words[11]).toBe('about')
})

it('throws an error if entropy is less than 16 bytes', async () => {
const entropy = await randomBytes(12)
Expand Down Expand Up @@ -64,5 +82,4 @@ describe('toEntropy', () => {
const mnemonic = Mnemonic.fromEntropy(entropy)
expect(mnemonic.toEntropy()).toEqual(entropy)
})

})

0 comments on commit 16c6887

Please sign in to comment.