2018-12-28 02:35:28 +01:00
|
|
|
import { Network } from './networks'
|
|
|
|
import * as NETWORKS from './networks'
|
2018-12-28 16:53:54 +01:00
|
|
|
import * as types from './types'
|
2018-06-25 08:24:37 +02:00
|
|
|
const ecc = require('tiny-secp256k1')
|
|
|
|
const randomBytes = require('randombytes')
|
|
|
|
const typeforce = require('typeforce')
|
|
|
|
const wif = require('wif')
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2018-06-25 08:24:37 +02:00
|
|
|
const isOptions = typeforce.maybe(typeforce.compile({
|
2018-05-22 08:33:43 +02:00
|
|
|
compressed: types.maybe(types.Boolean),
|
|
|
|
network: types.maybe(types.Network)
|
|
|
|
}))
|
2015-08-19 07:12:55 +02:00
|
|
|
|
2018-12-28 03:56:03 +01:00
|
|
|
interface ECPairOptions {
|
2018-12-28 02:35:28 +01:00
|
|
|
compressed?: boolean
|
|
|
|
network?: Network
|
2018-12-28 16:53:54 +01:00
|
|
|
rng?(arg0: Buffer): Buffer
|
2018-05-22 08:33:43 +02:00
|
|
|
}
|
2015-08-11 09:01:47 +02:00
|
|
|
|
2018-12-28 03:56:03 +01:00
|
|
|
export interface ECPairInterface {
|
|
|
|
compressed: boolean
|
|
|
|
network: Network
|
2018-12-30 03:23:28 +01:00
|
|
|
privateKey?: Buffer
|
|
|
|
publicKey?: Buffer
|
2018-12-28 03:56:03 +01:00
|
|
|
toWIF(): string
|
|
|
|
sign(hash: Buffer): Buffer
|
|
|
|
verify(hash: Buffer, signature: Buffer): Buffer
|
|
|
|
getPublicKey?(): Buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
class ECPair implements ECPairInterface {
|
2018-12-28 02:35:28 +01:00
|
|
|
compressed: boolean
|
|
|
|
network: Network
|
2018-12-30 03:23:28 +01:00
|
|
|
private __d?: Buffer
|
|
|
|
private __Q?: Buffer
|
2018-12-29 08:36:36 +01:00
|
|
|
|
|
|
|
constructor (d?: Buffer, Q?: Buffer, options?: ECPairOptions) {
|
2018-12-28 02:35:28 +01:00
|
|
|
if (options === undefined) options = {}
|
|
|
|
this.compressed = options.compressed === undefined ? true : options.compressed
|
|
|
|
this.network = options.network || NETWORKS.bitcoin
|
|
|
|
|
2018-12-30 03:23:28 +01:00
|
|
|
this.__d = undefined
|
|
|
|
this.__Q = undefined
|
2018-12-29 08:36:36 +01:00
|
|
|
if (d !== undefined) this.__d = d
|
|
|
|
if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed)
|
2018-12-28 02:35:28 +01:00
|
|
|
}
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2018-12-30 03:23:28 +01:00
|
|
|
get privateKey (): Buffer | undefined {
|
2018-12-28 02:35:28 +01:00
|
|
|
return this.__d
|
|
|
|
}
|
2015-03-19 03:25:41 +01:00
|
|
|
|
2018-12-30 03:23:28 +01:00
|
|
|
get publicKey (): Buffer | undefined {
|
2018-12-28 02:35:28 +01:00
|
|
|
if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__d, this.compressed)
|
|
|
|
return this.__Q
|
|
|
|
}
|
2015-03-19 03:25:41 +01:00
|
|
|
|
2018-12-28 02:35:28 +01:00
|
|
|
toWIF (): string {
|
|
|
|
if (!this.__d) throw new Error('Missing private key')
|
|
|
|
return wif.encode(this.network.wif, this.__d, this.compressed)
|
|
|
|
}
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2018-12-28 02:35:28 +01:00
|
|
|
sign (hash: Buffer): Buffer {
|
|
|
|
if (!this.__d) throw new Error('Missing private key')
|
|
|
|
return ecc.sign(hash, this.__d)
|
|
|
|
}
|
|
|
|
|
|
|
|
verify (hash: Buffer, signature: Buffer): Buffer {
|
|
|
|
return ecc.verify(hash, this.publicKey, signature)
|
|
|
|
}
|
2014-10-17 04:31:01 +02:00
|
|
|
}
|
|
|
|
|
2018-12-29 08:10:36 +01:00
|
|
|
function fromPrivateKey (buffer: Buffer, options?: ECPairOptions): ECPair {
|
2018-05-22 08:33:43 +02:00
|
|
|
typeforce(types.Buffer256bit, buffer)
|
|
|
|
if (!ecc.isPrivate(buffer)) throw new TypeError('Private key not in range [1, n)')
|
|
|
|
typeforce(isOptions, options)
|
|
|
|
|
2018-12-29 08:36:36 +01:00
|
|
|
return new ECPair(buffer, undefined, <ECPairOptions>options)
|
2018-05-22 08:33:43 +02:00
|
|
|
}
|
|
|
|
|
2018-12-29 08:10:36 +01:00
|
|
|
function fromPublicKey (buffer: Buffer, options?: ECPairOptions): ECPair {
|
2018-07-26 09:35:31 +02:00
|
|
|
typeforce(ecc.isPoint, buffer)
|
2018-05-22 08:33:43 +02:00
|
|
|
typeforce(isOptions, options)
|
2018-12-29 08:36:36 +01:00
|
|
|
return new ECPair(undefined, buffer, <ECPairOptions>options)
|
2018-05-22 08:33:43 +02:00
|
|
|
}
|
|
|
|
|
2018-12-29 08:36:36 +01:00
|
|
|
function fromWIF (string: string, network?: Network | Array<Network>): ECPair {
|
2018-06-25 08:37:45 +02:00
|
|
|
const decoded = wif.decode(string)
|
|
|
|
const version = decoded.version
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2017-01-06 03:41:51 +01:00
|
|
|
// list of networks?
|
2015-08-20 12:16:57 +02:00
|
|
|
if (types.Array(network)) {
|
2018-12-28 17:55:07 +01:00
|
|
|
network = <Network>(<Array<Network>>network).filter(function (x: Network) {
|
2017-01-06 03:41:51 +01:00
|
|
|
return version === x.wif
|
2016-02-24 11:08:40 +01:00
|
|
|
}).pop()
|
2016-02-25 03:48:29 +01:00
|
|
|
|
|
|
|
if (!network) throw new Error('Unknown network version')
|
2016-04-27 09:05:33 +02:00
|
|
|
|
2017-01-06 03:41:51 +01:00
|
|
|
// otherwise, assume a network object (or default to bitcoin)
|
2016-04-27 10:04:35 +02:00
|
|
|
} else {
|
|
|
|
network = network || NETWORKS.bitcoin
|
|
|
|
|
2018-12-28 16:53:54 +01:00
|
|
|
if (version !== (<Network>network).wif) throw new Error('Invalid network version')
|
2015-07-28 08:42:57 +02:00
|
|
|
}
|
|
|
|
|
2018-05-22 08:33:43 +02:00
|
|
|
return fromPrivateKey(decoded.privateKey, {
|
2015-08-20 12:16:57 +02:00
|
|
|
compressed: decoded.compressed,
|
2018-12-28 16:53:54 +01:00
|
|
|
network: <Network>network
|
2014-10-17 04:31:01 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-12-29 08:10:36 +01:00
|
|
|
function makeRandom (options?: ECPairOptions): ECPair {
|
2018-05-22 08:33:43 +02:00
|
|
|
typeforce(isOptions, options)
|
2018-12-28 02:35:28 +01:00
|
|
|
if (options === undefined) options = {}
|
2018-06-25 08:37:45 +02:00
|
|
|
const rng = options.rng || randomBytes
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2018-05-22 08:33:43 +02:00
|
|
|
let d
|
2015-08-21 08:46:18 +02:00
|
|
|
do {
|
2018-05-22 08:33:43 +02:00
|
|
|
d = rng(32)
|
|
|
|
typeforce(types.Buffer256bit, d)
|
|
|
|
} while (!ecc.isPrivate(d))
|
2014-10-17 04:31:01 +02:00
|
|
|
|
2018-05-22 08:33:43 +02:00
|
|
|
return fromPrivateKey(d, options)
|
2015-09-21 09:37:21 +02:00
|
|
|
}
|
|
|
|
|
2018-12-28 02:35:28 +01:00
|
|
|
export {
|
2018-05-22 08:33:43 +02:00
|
|
|
makeRandom,
|
|
|
|
fromPrivateKey,
|
|
|
|
fromPublicKey,
|
|
|
|
fromWIF
|
2014-10-17 04:31:01 +02:00
|
|
|
}
|