From e3da92d1ee8182aec4370bb1a4e347b462684d2e Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Sun, 22 Jul 2018 20:05:14 -0400 Subject: [PATCH] Lazy load the elliptic curve; also fixed circular dependencies internal to the library that cause issues in browserify. --- src.ts/utils/secp256k1.ts | 28 ++++++++++++++-------------- src.ts/utils/transaction.ts | 2 +- src.ts/wallet/hdnode.ts | 4 +++- src.ts/wallet/signing-key.ts | 11 ----------- 4 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src.ts/utils/secp256k1.ts b/src.ts/utils/secp256k1.ts index 8e65b1faa..5c660fd50 100644 --- a/src.ts/utils/secp256k1.ts +++ b/src.ts/utils/secp256k1.ts @@ -8,11 +8,20 @@ import { arrayify, hexlify, hexZeroPad, splitSignature } from './bytes'; import { hashMessage } from './hash'; import { keccak256 } from './keccak256'; import { defineReadOnly } from './properties'; +import { ec as EC } from 'elliptic'; import { Arrayish, Signature } from './types'; import * as errors from './errors'; +let _curve: EC = null +function getCurve() { + if (!_curve) { + _curve = new EC('secp256k1'); + } + return _curve; +} + export class KeyPair { @@ -24,7 +33,7 @@ export class KeyPair { readonly publicKeyBytes: Uint8Array; constructor(privateKey: Arrayish) { - let keyPair = curve.keyFromPrivate(arrayify(privateKey)); + let keyPair = getCurve().keyFromPrivate(arrayify(privateKey)); defineReadOnly(this, 'privateKey', hexlify(keyPair.priv.toArray('be', 32))); defineReadOnly(this, 'publicKey', '0x' + keyPair.getPublic(false, 'hex')); @@ -33,7 +42,7 @@ export class KeyPair { } sign(digest: Arrayish): Signature { - let keyPair = curve.keyFromPrivate(arrayify(this.privateKey)); + let keyPair = getCurve().keyFromPrivate(arrayify(this.privateKey)); let signature = keyPair.sign(arrayify(digest), {canonical: true}); return { recoveryParam: signature.recoveryParam, @@ -50,7 +59,7 @@ export function recoverPublicKey(digest: Arrayish, signature: Signature): string r: arrayify(signature.r), s: arrayify(signature.s) }; - return '0x' + curve.recoverPubKey(arrayify(digest), sig, signature.recoveryParam).encode('hex', false); + return '0x' + getCurve().recoverPubKey(arrayify(digest), sig, signature.recoveryParam).encode('hex', false); } export function computePublicKey(key: Arrayish, compressed?: boolean): string { @@ -66,11 +75,11 @@ export function computePublicKey(key: Arrayish, compressed?: boolean): string { } else if (bytes.length === 33) { if (compressed) { return hexlify(bytes); } - return '0x' + curve.keyFromPublic(bytes).getPublic(false, 'hex'); + return '0x' + getCurve().keyFromPublic(bytes).getPublic(false, 'hex'); } else if (bytes.length === 65) { if (!compressed) { return hexlify(bytes); } - return '0x' + curve.keyFromPublic(bytes).getPublic(true, 'hex'); + return '0x' + getCurve().keyFromPublic(bytes).getPublic(true, 'hex'); } errors.throwError('invalid public or private key', errors.INVALID_ARGUMENT, { arg: 'key', value: '[REDACTED]' }); @@ -102,12 +111,3 @@ export function verifyMessage(message: Arrayish | string, signature: Signature | ); } -// !!!!!! IMPORTANT !!!!!!!! -// -// This import MUST be at the bottom, otehrwise browserify executes several imports -// BEFORE they are exported, resulting in undefined - -import { ec as EC } from 'elliptic'; -const curve = new EC('secp256k1'); - -export const N = '0x' + curve.n.toString(16); diff --git a/src.ts/utils/transaction.ts b/src.ts/utils/transaction.ts index b6aee9374..1ef66d5ec 100644 --- a/src.ts/utils/transaction.ts +++ b/src.ts/utils/transaction.ts @@ -3,6 +3,7 @@ import { getAddress } from './address'; import { bigNumberify, ConstantZero } from './bignumber'; import { arrayify, hexlify, hexZeroPad, splitSignature, stripZeros, } from './bytes'; import { keccak256 } from './keccak256'; +import { recoverAddress } from './secp256k1'; import * as RLP from './rlp'; @@ -159,4 +160,3 @@ export function parse(rawTransaction: Arrayish): Transaction { return tx; } -import { recoverAddress } from './secp256k1'; diff --git a/src.ts/wallet/hdnode.ts b/src.ts/wallet/hdnode.ts index 2e3c26888..011bb5fe7 100644 --- a/src.ts/wallet/hdnode.ts +++ b/src.ts/wallet/hdnode.ts @@ -17,9 +17,11 @@ import { toUtf8Bytes, UnicodeNormalizationForm } from '../utils/utf8'; import { pbkdf2 } from '../utils/pbkdf2'; import { computeHmac } from '../utils/hmac'; import { defineReadOnly } from '../utils/properties'; -import { KeyPair, N } from '../utils/secp256k1'; +import { KeyPair } from '../utils/secp256k1'; import { sha256 } from '../utils/sha2'; +const N = bigNumberify("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); + import { Arrayish, HDNode as _HDNode ,Wordlist } from '../utils/types'; import * as errors from '../utils/errors'; diff --git a/src.ts/wallet/signing-key.ts b/src.ts/wallet/signing-key.ts index 9c9f87f7c..521e74cfe 100644 --- a/src.ts/wallet/signing-key.ts +++ b/src.ts/wallet/signing-key.ts @@ -67,14 +67,3 @@ export class SigningKey { return this.keyPair.sign(digest); } } -/* -export function recoverAddress(digest: Arrayish, signature: Signature): string { - return computeAddress(recoverPublicKey(digest, signature)); -} - -export function computeAddress(key: string): string { - // Strip off the leading "0x04" - let publicKey = '0x' + computePublicKey(key).slice(4); - return getAddress('0x' + keccak256(publicKey).substring(26)); -} -*/