This repository has been archived by the owner on Jul 10, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 14
/
wallet.js
177 lines (157 loc) · 5.62 KB
/
wallet.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
'use strict'
const secp256k1 = require('secp256k1')
const Bitcoin = require('./bitcoin.js')
const Cosmos = require('./cosmos.js')
const Ethereum = require('./ethereum.js')
const bip39 = require('bip39')
const { HDNode } = require('bitcoinjs-lib')
const { xor } = require('./util.js')
const { sha2 } = require('./hash.js')
const entropySalt = 'YOU COULD REPLACE THIS WITH ANYTHING'
function generateMnemonic () {
let mnemonic = bip39.generateMnemonic()
let entropyHex = bip39.mnemonicToEntropy(mnemonic)
let entropyBuf = new Buffer(entropyHex, 'hex')
// console.log("before", entropyBuf, mnemonic)
let salt = sha2(entropySalt)
salt = salt.slice(0, 16)
// console.log("salt", salt)
entropyBuf = xor(entropyBuf, new Buffer(salt))
entropyHex = entropyBuf.toString('hex')
mnemonic = bip39.entropyToMnemonic(entropyHex)
// console.log("after", entropyBuf, mnemonic)
return mnemonic
}
function splitMnemonic (mnemonic) {
let eHex = bip39.mnemonicToEntropy(mnemonic)
let eBuf = new Buffer(eHex, 'hex')
let one = bip39.generateMnemonic()
let oneHex = bip39.mnemonicToEntropy(one)
let oneBuf = new Buffer(oneHex, 'hex')
let twoBuf = xor(eBuf, oneBuf)
let twoHex = twoBuf.toString('hex')
let two = bip39.entropyToMnemonic(twoHex)
return { one, two }
}
function joinMnemonic (one, two) {
let oneHex = bip39.mnemonicToEntropy(one)
let oneBuf = new Buffer(oneHex, 'hex')
let twoHex = bip39.mnemonicToEntropy(two)
let twoBuf = new Buffer(twoHex, 'hex')
let eBuf = xor(oneBuf, twoBuf)
let eHex = eBuf.toString('hex')
let mnemonic = bip39.entropyToMnemonic(eHex)
return mnemonic
}
function deriveWallet (mnemonic) {
let privateKeys = derivePrivateKeys(mnemonic)
let publicKeys = derivePublicKeys(privateKeys)
let addresses = deriveAddresses(publicKeys)
return { privateKeys, publicKeys, addresses }
}
function deriveMasterKey (mnemonic) {
// seed must be 12 or more space-separated words
var words = mnemonic.trim().split(/\s+/g)
if (words.length < 12) {
throw Error('Mnemonic must be at least 12 words')
}
// throws if mnemonic is invalid
bip39.mnemonicToEntropy(mnemonic)
var seed = bip39.mnemonicToSeed(mnemonic)
var masterKey = HDNode.fromSeedBuffer(seed)
return masterKey
}
function derivePrivateKeys (mnemonic) {
var masterKey = deriveMasterKey(mnemonic)
// bip32 derived wallet: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
// single quote == hardened derivation
// derivation path: m/purpose/cointype/account/...
// purpose: the BIP which sets the spec: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
// see motivation: https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki
// cointype: not clear where source of truth is but
// btc = 0
// eth = 60
// dfn = 223
// atom = 118 (?) // TODO
var hdPathAtom = "m/44'/118'/0'/0/0" // key controlling ATOM allocation
var hdPathETHIntermediate = "m/44'/60'/0'/0/0" // ETH key for emergency return address
var hdPathBTCIntermediate = "m/44'/0'/0'/0/0" // BTC key forwarding donation for hdPathAtom key
var cosmosHD = masterKey.derivePath(hdPathAtom)
var ethereumHD = masterKey.derivePath(hdPathETHIntermediate)
var bitcoinHD = masterKey.derivePath(hdPathBTCIntermediate)
// NOTE: we want to make sure private keys are always 32 bytes
// else we may have trouble. See the bitcore fiasco for more:
// https://github.com/bitpay/bitcore-lib/issues/47
// https://github.com/bitpay/bitcore-lib/pull/97
var cosmos = padPrivKey(cosmosHD.keyPair.d.toBuffer())
var bitcoin = padPrivKey(bitcoinHD.keyPair.d.toBuffer())
var ethereum = padPrivKey(ethereumHD.keyPair.d.toBuffer())
return { cosmos, bitcoin, ethereum }
}
function derivePublicKeys (priv) {
// bitcoin and cosmos use compressed pubkey of 33 bytes.
// ethereum uses uncompressed 64-byte pubkey without the openssl prefix (0x04).
let bitcoin = secp256k1.publicKeyCreate(priv.bitcoin, true)
let cosmos = secp256k1.publicKeyCreate(priv.cosmos, true)
let ethereum = secp256k1.publicKeyCreate(priv.ethereum, false).slice(-64)
return { cosmos, bitcoin, ethereum }
}
// cosmos and eth are 0x hex, bitcoin is base58check
function deriveAddresses (pub) {
let cosmos = Cosmos.getAddress(pub.cosmos)
let bitcoin = Bitcoin.getAddress(pub.bitcoin)
let ethereum = Ethereum.getAddress(pub.ethereum)
return { cosmos, bitcoin, ethereum }
}
module.exports = {
generateMnemonic,
splitMnemonic,
joinMnemonic,
deriveWallet
}
/*
// test
var list = []
var N = 200
for (let i = 0; i < N; i++){
var mnemonic = generateMnemonic()
var w = deriveWallet(mnemonic)
var obj = {
mnemonic: mnemonic,
master: padPrivKey(deriveMasterKey(mnemonic).keyPair.d.toBuffer()).toString('hex'),
seed: bip39.mnemonicToSeed(mnemonic).toString('hex'),
priv: w.privateKeys.cosmos.toString('hex'),
pub: w.publicKeys.cosmos.toString('hex'),
addr: w.addresses.cosmos.toString('hex'),
}
list.push(obj)
}
console.log(JSON.stringify(list));
*/
/*
var seed = generateSeed()
var w = deriveWallet(seed)
var obj = {
seed: seed,
privateKeys: {
cosmos: w.privateKeys.cosmos.toString('hex'),
bitcoin: w.privateKeys.bitcoin.toString('hex'),
ethereum: w.privateKeys.ethereum.toString('hex')
},
publicKeys: {
cosmos: w.publicKeys.cosmos.toString('hex'),
bitcoin: w.publicKeys.bitcoin.toString('hex'),
ethereum: w.publicKeys.ethereum.toString('hex')
},
addresses: {
cosmos: w.addresses.cosmos,
bitcoin: w.addresses.bitcoin,
ethereum: w.addresses.ethereum
}
}
console.log(obj)
*/
function padPrivKey (privB) {
var privHex = privB.toString('hex')
return Buffer(('0000000000000000' + privHex).slice(-64), 'hex')
}