1 | var baddress = require('./address')
|
2 | var bcrypto = require('./crypto')
|
3 | var ecdsa = require('./ecdsa')
|
4 | var randomBytes = require('randombytes')
|
5 | var typeforce = require('typeforce')
|
6 | var types = require('./types')
|
7 | var wif = require('wif')
|
8 |
|
9 | var NETWORKS = require('./networks')
|
10 | var BigInteger = require('bigi')
|
11 |
|
12 | var ecurve = require('ecurve')
|
13 | var secp256k1 = ecdsa.__curve
|
14 |
|
15 | function ECPair (d, Q, options) {
|
16 | if (options) {
|
17 | typeforce({
|
18 | compressed: types.maybe(types.Boolean),
|
19 | network: types.maybe(types.Network)
|
20 | }, options)
|
21 | }
|
22 |
|
23 | options = options || {}
|
24 |
|
25 | if (d) {
|
26 | if (d.signum() <= 0) throw new Error('Private key must be greater than 0')
|
27 | if (d.compareTo(secp256k1.n) >= 0) throw new Error('Private key must be less than the curve order')
|
28 | if (Q) throw new TypeError('Unexpected publicKey parameter')
|
29 |
|
30 | this.d = d
|
31 | } else {
|
32 | typeforce(types.ECPoint, Q)
|
33 |
|
34 | this.__Q = Q
|
35 | }
|
36 |
|
37 | this.compressed = options.compressed === undefined ? true : options.compressed
|
38 | this.network = options.network || NETWORKS.bitcoin
|
39 | }
|
40 |
|
41 | Object.defineProperty(ECPair.prototype, 'Q', {
|
42 | get: function () {
|
43 | if (!this.__Q && this.d) {
|
44 | this.__Q = secp256k1.G.multiply(this.d)
|
45 | }
|
46 |
|
47 | return this.__Q
|
48 | }
|
49 | })
|
50 |
|
51 | ECPair.fromPublicKeyBuffer = function (buffer, network) {
|
52 | var Q = ecurve.Point.decodeFrom(secp256k1, buffer)
|
53 |
|
54 | return new ECPair(null, Q, {
|
55 | compressed: Q.compressed,
|
56 | network: network
|
57 | })
|
58 | }
|
59 |
|
60 | ECPair.fromWIF = function (string, network) {
|
61 | var decoded = wif.decode(string)
|
62 | var version = decoded.version
|
63 |
|
64 |
|
65 | if (types.Array(network)) {
|
66 | network = network.filter(function (network) {
|
67 | return version === network.wif
|
68 | }).pop()
|
69 |
|
70 | if (!network) throw new Error('Unknown network version')
|
71 |
|
72 |
|
73 | } else {
|
74 | network = network || NETWORKS.bitcoin
|
75 |
|
76 | if (version !== network.wif) throw new Error('Invalid network version')
|
77 | }
|
78 |
|
79 | var d = BigInteger.fromBuffer(decoded.privateKey)
|
80 |
|
81 | return new ECPair(d, null, {
|
82 | compressed: decoded.compressed,
|
83 | network: network
|
84 | })
|
85 | }
|
86 |
|
87 | ECPair.makeRandom = function (options) {
|
88 | options = options || {}
|
89 |
|
90 | var rng = options.rng || randomBytes
|
91 |
|
92 | var d
|
93 | do {
|
94 | var buffer = rng(32)
|
95 | typeforce(types.Buffer256bit, buffer)
|
96 |
|
97 | d = BigInteger.fromBuffer(buffer)
|
98 | } while (d.signum() <= 0 || d.compareTo(secp256k1.n) >= 0)
|
99 |
|
100 | return new ECPair(d, null, options)
|
101 | }
|
102 |
|
103 | ECPair.prototype.getAddress = function () {
|
104 | return baddress.toBase58Check(bcrypto.hash160(this.getPublicKeyBuffer()), this.getNetwork().pubKeyHash)
|
105 | }
|
106 |
|
107 | ECPair.prototype.getNetwork = function () {
|
108 | return this.network
|
109 | }
|
110 |
|
111 | ECPair.prototype.getPublicKeyBuffer = function () {
|
112 | return this.Q.getEncoded(this.compressed)
|
113 | }
|
114 |
|
115 | ECPair.prototype.sign = function (hash) {
|
116 | if (!this.d) throw new Error('Missing private key')
|
117 |
|
118 | return ecdsa.sign(hash, this.d)
|
119 | }
|
120 |
|
121 | ECPair.prototype.toWIF = function () {
|
122 | if (!this.d) throw new Error('Missing private key')
|
123 |
|
124 | return wif.encode(this.network.wif, this.d.toBuffer(32), this.compressed)
|
125 | }
|
126 |
|
127 | ECPair.prototype.verify = function (hash, signature) {
|
128 | return ecdsa.verify(hash, signature, this.Q)
|
129 | }
|
130 |
|
131 | module.exports = ECPair
|