Skip to content

Commit

Permalink
refactor: more deps gone
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasbrugneaux committed Feb 13, 2024
1 parent 92abb08 commit ed5986c
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 145 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
},
"resolutions": {
"ganache": "npm:@celo/[email protected]",
"bip39": "https://github.com/bitcoinjs/bip39#a7ecbfe2e60d0214ce17163d610cad9f7b23140c",
"blind-threshold-bls": "npm:@celo/[email protected]",
"@types/bn.js": "4.11.6",
"bignumber.js": "9.0.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@
"@oclif/plugin-not-found": "^3.0.9",
"@oclif/plugin-plugins": "^4.1.17",
"@oclif/plugin-warn-if-update-available": "^3.0.9",
"@scure/bip32": "^1.3.3",
"@types/command-exists": "^1.2.3",
"bignumber.js": "9.0.0",
"bip32": "3.1.0",
"chalk": "^2.4.2",
"command-exists": "^1.2.9",
"debug": "^4.1.1",
Expand Down
9 changes: 3 additions & 6 deletions packages/sdk/cryptographic-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,13 @@
"@noble/ciphers": "0.4.1",
"@noble/curves": "1.3.0",
"@noble/hashes": "1.3.3",
"@scure/bip32": "^1.3.3",
"@scure/bip39": "^1.2.2",
"@types/bn.js": "^5.1.0",
"@types/node": "^18.7.16",
"@types/randombytes": "^2.0.0",
"bigi": "^1.4.2",
"bip32": "^3.1.0",
"bip39": "https://github.com/bitcoinjs/bip39#a7ecbfe2e60d0214ce17163d610cad9f7b23140c",
"buffer-reverse": "^1.0.1",
"ethereum-cryptography": "1.2.0",
"randombytes": "^2.0.1",
"tiny-secp256k1": "2.2.1"
"ethereum-cryptography": "1.2.0"
},
"devDependencies": {
"@celo/typescript": "0.0.1"
Expand Down
7 changes: 4 additions & 3 deletions packages/sdk/cryptographic-utils/src/account.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MnemonicLanguages } from '@celo/base/lib/account'
import * as bip39 from 'bip39'
import * as bip39 from '@scure/bip39'
import {
generateKeys,
generateMnemonic,
Expand All @@ -10,6 +10,7 @@ import {
suggestMnemonicCorrections,
validateMnemonic,
} from './account'
import wordlists from './wordlists'

describe('AccountUtils', () => {
describe('.generateMnemonic()', () => {
Expand All @@ -32,7 +33,7 @@ describe('AccountUtils', () => {
// This validates against all languages
expect(validateMnemonic(mnemonic)).toBeTruthy()
// This validates using a specific wordlist
expect(bip39.validateMnemonic(mnemonic, bip39.wordlists[languageName])).toBeTruthy()
expect(bip39.validateMnemonic(mnemonic, wordlists[language])).toBeTruthy()
})
}
})
Expand Down Expand Up @@ -69,7 +70,7 @@ describe('AccountUtils', () => {
// This validates against all languages
expect(validateMnemonic(mnemonic)).toBeTruthy()
// This validates using a specific wordlist
expect(bip39.validateMnemonic(mnemonic, bip39.wordlists[languageName])).toBeTruthy()
expect(bip39.validateMnemonic(mnemonic, wordlists[language])).toBeTruthy()
})
}
})
Expand Down
86 changes: 34 additions & 52 deletions packages/sdk/cryptographic-utils/src/account.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
Bip39,
CELO_DERIVATION_PATH_BASE,
MnemonicLanguages,
MnemonicStrength,
Expand All @@ -8,17 +7,18 @@ import {
import { normalizeAccents } from '@celo/base/lib/string'
import { privateKeyToAddress } from '@celo/utils/lib/address'
import { levenshteinDistance } from '@celo/utils/lib/levenshtein'
// TODO replace by @scure/bip32
import BIP32Factory from 'bip32'
// TODO replace by @scure/bip32
import * as bip39 from 'bip39'
// TODO replace by @noble/hashes/sha3 { keccak_256 }
import { keccak256 } from 'ethereum-cryptography/keccak'
import { utf8ToBytes } from 'ethereum-cryptography/utils'
import randomBytes from 'randombytes'

// TODO replace by @noble/curves/secp256k1
import * as ecc from 'tiny-secp256k1'
import { keccak_256 } from '@noble/hashes/sha3'
import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils'
import { HDKey } from '@scure/bip32'
import {
validateMnemonic as _validateMnemonic,
entropyToMnemonic,
mnemonicToSeed,
mnemonicToSeedSync,
} from '@scure/bip39'
import { randomBytes } from 'crypto'
import wordlists from './wordlists'

// Exports moved to @celo/base, forwarding them
// here for backwards compatibility
export {
Expand All @@ -28,12 +28,11 @@ export {
MnemonicStrength,
RandomNumberGenerator,
} from '@celo/base/lib/account'
const bip32 = BIP32Factory(ecc)

function defaultGenerateMnemonic(
strength?: number,
rng?: RandomNumberGenerator,
wordlist?: string[]
wordlist: string[] = wordlists[MnemonicLanguages.english]
): Promise<string> {
return new Promise((resolve, reject) => {
strength = strength || 128
Expand All @@ -43,30 +42,30 @@ function defaultGenerateMnemonic(
if (error) {
reject(error)
} else {
resolve(bip39.entropyToMnemonic(randomBytesBuffer.toString('hex'), wordlist))
resolve(entropyToMnemonic(randomBytesBuffer, wordlist))
}
})
})
}

const bip39Wrapper: Bip39 = {
mnemonicToSeedSync: bip39.mnemonicToSeedSync,
mnemonicToSeed: bip39.mnemonicToSeed,
const bip39Wrapper = {
mnemonicToSeedSync: mnemonicToSeedSync,
mnemonicToSeed: mnemonicToSeed,
generateMnemonic: defaultGenerateMnemonic,
validateMnemonic: bip39.validateMnemonic,
validateMnemonic: _validateMnemonic,
}

export async function generateMnemonic(
strength: MnemonicStrength = MnemonicStrength.s256_24words,
language?: MnemonicLanguages,
bip39ToUse: Bip39 = bip39Wrapper
bip39ToUse = bip39Wrapper
): Promise<string> {
return bip39ToUse.generateMnemonic(strength, undefined, getWordList(language))
}

export function validateMnemonic(
mnemonic: string,
bip39ToUse: Bip39 = bip39Wrapper,
bip39ToUse = bip39Wrapper,
language?: MnemonicLanguages
) {
if (language !== undefined) {
Expand Down Expand Up @@ -166,28 +165,8 @@ export function formatNonAccentedCharacters(mnemonic: string) {
}

// Unify the bip39.wordlists (otherwise depends on the instance of the bip39)
function getWordList(language?: MnemonicLanguages): string[] {
// Use exhaustive switch to ensure that every language is accounted for.
switch (language ?? MnemonicLanguages.english) {
case MnemonicLanguages.chinese_simplified:
return bip39.wordlists.chinese_simplified
case MnemonicLanguages.chinese_traditional:
return bip39.wordlists.chinese_traditional
case MnemonicLanguages.english:
return bip39.wordlists.english
case MnemonicLanguages.french:
return bip39.wordlists.french
case MnemonicLanguages.italian:
return bip39.wordlists.italian
case MnemonicLanguages.japanese:
return bip39.wordlists.japanese
case MnemonicLanguages.korean:
return bip39.wordlists.korean
case MnemonicLanguages.spanish:
return bip39.wordlists.spanish
case MnemonicLanguages.portuguese:
return bip39.wordlists.portuguese
}
function getWordList(language: MnemonicLanguages = MnemonicLanguages.english): string[] {
return wordlists[language]
}

export function getAllLanguages(): MnemonicLanguages[] {
Expand Down Expand Up @@ -410,7 +389,7 @@ export async function generateKeys(
password?: string,
changeIndex: number = 0,
addressIndex: number = 0,
bip39ToUse: Bip39 = bip39Wrapper,
bip39ToUse = bip39Wrapper,
derivationPath: string = CELO_DERIVATION_PATH_BASE
): Promise<{ privateKey: string; publicKey: string; address: string }> {
const seed: Buffer = await generateSeed(mnemonic, password, bip39ToUse)
Expand All @@ -425,7 +404,7 @@ export function generateDeterministicInviteCode(
changeIndex: number = 0,
derivationPath: string = CELO_DERIVATION_PATH_BASE
): { privateKey: string; publicKey: string } {
const seed = keccak256(utf8ToBytes(recipientPhoneHash + recipientPepper)) as Buffer
const seed = keccak_256(utf8ToBytes(recipientPhoneHash + recipientPepper)) as Buffer
return generateKeysFromSeed(seed, changeIndex, addressIndex, derivationPath)
}

Expand All @@ -434,10 +413,10 @@ export function generateDeterministicInviteCode(
export async function generateSeed(
mnemonic: string,
password?: string,
bip39ToUse: Bip39 = bip39Wrapper,
bip39ToUse = bip39Wrapper,
keyByteLength: number = 64
): Promise<Buffer> {
let seed: Buffer = await bip39ToUse.mnemonicToSeed(mnemonic, password)
let seed = Buffer.from(await bip39ToUse.mnemonicToSeed(mnemonic, password))
if (keyByteLength > 0 && seed.byteLength > keyByteLength) {
const bufAux = Buffer.allocUnsafe(keyByteLength)
seed.copy(bufAux, 0, 0, keyByteLength)
Expand All @@ -452,18 +431,21 @@ export function generateKeysFromSeed(
addressIndex: number = 0,
derivationPath: string = CELO_DERIVATION_PATH_BASE
): { privateKey: string; publicKey: string; address: string } {
const node = bip32.fromSeed(seed)
const newNode = node.derivePath(
const node = HDKey.fromMasterSeed(seed)
const newNode = node.derive(
`${derivationPath ? `${derivationPath}/` : ''}${changeIndex}/${addressIndex}`
)
if (!newNode.privateKey) {
// As we are generating the node from a seed, the node will always have a private key and this would never happened
throw new Error('utils-accounts@generateKeys: invalid node to derivate')
}
const privateKey = bytesToHex(newNode.privateKey)
const publicKey = bytesToHex(newNode.publicKey!)

return {
privateKey: newNode.privateKey.toString('hex'),
publicKey: newNode.publicKey.toString('hex'),
address: privateKeyToAddress(newNode.privateKey.toString('hex')),
privateKey,
publicKey,
address: privateKeyToAddress(privateKey),
}
}

Expand Down
15 changes: 8 additions & 7 deletions packages/sdk/cryptographic-utils/src/bls.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { BLS } from '@celo/bls12377js'
// this is an implementation of a subset of BLS12-377
import { isValidAddress } from '@celo/utils/lib/address'
import { keccak256 } from 'ethereum-cryptography/keccak'
const BigInteger = require('bigi')
import { keccak_256 } from '@noble/hashes/sha3'
import { bytesToHex } from '@noble/hashes/utils'
const reverse = require('buffer-reverse')

const n = BigInteger.fromHex('12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001', 16)
const n = BigInt('0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001')

const MODULUSMASK = 31
export const BLS_PUBLIC_KEY_SIZE = 96
Expand All @@ -22,17 +22,18 @@ export const blsPrivateKeyToProcessedPrivateKey = (privateKeyHex: string) => {
iBuffer,
originalPrivateKeyBytes,
])
const privateKeyBLSBytes = keccak256(keyBytes)
const privateKeyBLSBytes = keccak_256(keyBytes)

// eslint-disable-next-line no-bitwise
privateKeyBLSBytes[0] &= MODULUSMASK

const privateKeyNum = BigInteger.fromBuffer(privateKeyBLSBytes)
if (privateKeyNum.compareTo(n) >= 0) {
const _privateKeyHex = `0x${bytesToHex(privateKeyBLSBytes)}`
const privateKeyNum = BigInt(_privateKeyHex)
if (privateKeyNum >= n) {
continue
}

const privateKeyBytes = reverse(privateKeyNum.toBuffer())
const privateKeyBytes = reverse(Buffer.from(_privateKeyHex, 'hex'))

return privateKeyBytes
}
Expand Down
25 changes: 25 additions & 0 deletions packages/sdk/cryptographic-utils/src/wordlists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { MnemonicLanguages } from '@celo/base/lib/account'

import { wordlist as english } from '@scure/bip39/wordlists/english'
import { wordlist as french } from '@scure/bip39/wordlists/french'
import { wordlist as italian } from '@scure/bip39/wordlists/italian'
import { wordlist as japanese } from '@scure/bip39/wordlists/japanese'
import { wordlist as korean } from '@scure/bip39/wordlists/korean'
import { wordlist as portuguese } from '@scure/bip39/wordlists/portuguese'
import { wordlist as chinese_simplified } from '@scure/bip39/wordlists/simplified-chinese'
import { wordlist as spanish } from '@scure/bip39/wordlists/spanish'
import { wordlist as chinese_traditional } from '@scure/bip39/wordlists/traditional-chinese'

const wordlists: Record<MnemonicLanguages, string[]> = {
[MnemonicLanguages.english]: english,
[MnemonicLanguages.french]: french,
[MnemonicLanguages.italian]: italian,
[MnemonicLanguages.japanese]: japanese,
[MnemonicLanguages.korean]: korean,
[MnemonicLanguages.portuguese]: portuguese,
[MnemonicLanguages.chinese_simplified]: chinese_simplified,
[MnemonicLanguages.spanish]: spanish,
[MnemonicLanguages.chinese_traditional]: chinese_traditional,
} as const

export default wordlists
Loading

0 comments on commit ed5986c

Please sign in to comment.