-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbitcoin.js
155 lines (139 loc) · 5.74 KB
/
bitcoin.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
const nacl = require("tweetnacl");
nacl.util = require("tweetnacl-util");
const secp256k1 = require('secp256k1');
const bitcoinjs = require('bitcoinjs-lib');
const typeConverter = require("./typeConverter");
const masterKeySeed = require("./masterKeySeed");
const bip32 = require("bip32");
const walletValidator = require('wallet-address-validator');
const util = require('./util');
const {ErrorType, ErrorUtil} = require("./middleUtility/main").TierError;
const {requestErrors} = ErrorType;
/* ***************************** Secp256k1 For BTC ***************************** */
// derive private key from masterKeySeed
// input : masterKeySeed is a 64 bytes buffer
// input : keyPath is a string
// input : network should be the network object of one of "BTCOIN", "TESTNET" or "REGTEST"
// return : promise containing error object or derivedPrivateKey which is a 32 bytes buffer
function derivePrivateKey(masterKeySeed, keyPath, network) {
return new Promise((resolve, reject) => {
// derive BitCoin master key node from masterKeySeed
try {
const masterNode = bip32.fromSeed(masterKeySeed, network);
const keyPair = masterNode.derivePath(keyPath);
resolve(keyPair)
} catch (err) {
reject(ErrorUtil.errorWrap(requestErrors.FailedToDeriveNewKey))
}
})
}
// verify BTC private key
// input : BitCoin privateKey which is a 32 bytes buffer
// return : privateKey verifyResult (true || false)
function verifyPrivateKey(privateKey) {
return secp256k1.privateKeyVerify(privateKey)
}
// derive publicKey from privateKey
// input : privateKey should be 32 bytes buffer
// return : derived privateKey's publicKey which is a 33 bytes hex string with chain prefix 0x02 or 0x03
function derivePublicKey(keyPair) {
return typeConverter.bufferToHexStr(keyPair.publicKey)
}
// derive P2PKH address
// input : publicKey should be a 33 bytes hex string with chain prefix
// return : 34 chars length base58 encoding P2PKH address
function deriveP2PKHAddress(publicKey, network) {
const pubkey = typeConverter.hexStrToBuffer(publicKey);
return bitcoinjs.payments.p2pkh({pubkey, network}).address
}
// verify P2PKH or P2SH address
function verifyAddress(address) {
if (!util.isValidString(address)) return false;
return walletValidator.validate(address, 'BTC')
}
// derive P2PK publicKey
// input : publicKey should be a 33 bytes hex string with chain prefix
// return : 33 bytes hex string public key with chain prefix
function deriveP2PKPubKey(publicKey) {
// const pubkey = typeConverter.hexStrToBuffer(publicKey);
// bitcoinjs.payments.p2pk({pubkey}).pubkey;
return publicKey
}
// verify P2PK public key
function verifyP2PKPublicKey(publicKey) {
if (!util.isValidString(publicKey)) return false;
return secp256k1.publicKeyVerify(typeConverter.hexStrToBuffer(publicKey))
}
// TODO : no need for now
function deriveP2WPKHAddress(publicKey) {
const pubkey = typeConverter.hexStrToBuffer(publicKey);
return bitcoinjs.payments.p2wpkh({pubkey}).address
}
// TODO : no need for now
function deriveP2WSHAddress(publicKey) {
const pubkey = typeConverter.hexStrToBuffer(publicKey);
return bitcoinjs.payments.p2wsh({pubkey}).address
}
// TODO : no need for now
function deriveP2SHAddress(publicKey) {
const pubkey = typeConverter.hexStrToBuffer(publicKey);
return bitcoinjs.payments.p2sh({pubkey}).address
}
// TODO : no need for now
function deriveP2MSAddress(publicKey) {
const pubkey = typeConverter.hexStrToBuffer(publicKey);
return bitcoinjs.payments.p2ms({pubkey}).address
}
// sign BitCoin tx
// input : encryptedMasterKeySeed is a string
// input : keyPath is a string
// input : message should be a hex string
// input : password is plaintext
// input : network should be the network object of one of "BTCOIN", "TESTNET" or "REGTEST"
// return : promise containing error object or signature which is a hex string
async function signForSignature({message, password, encryptedMasterKeySeed, keyPath, network}) {
let decryptedMasterKeySeed = await masterKeySeed.masterKeySeedDecryption(password, encryptedMasterKeySeed).catch(error => {
return Promise.reject(error)
});
let derivedKeyPair = await derivePrivateKey(decryptedMasterKeySeed, keyPath, network).catch(error => {
return Promise.reject(error)
});
// use WIF to sign, not private key itself
const signer = bitcoinjs.ECPair.fromWIF(derivedKeyPair.toWIF(), network);
let tx;
try {
tx = bitcoinjs.Transaction.fromHex(message);
} catch (err) {
return Promise.reject(ErrorUtil.errorWrap(requestErrors.InvalidBTCtxMessage))
}
const txBuilder = bitcoinjs.TransactionBuilder.fromTransaction(tx, network);
txBuilder.sign(0, signer);
const signedTx = txBuilder.build();
const sigScript = signedTx.ins[0].script;
decryptedMasterKeySeed = null;
derivedKeyPair = null;
return Promise.resolve({signature: typeConverter.bufferToHexStr(sigScript)})
}
// verify BTC tx signature
// input : message 32 bytes hex string
// input : signature 64 bytes hex string
// input : publicKey 33 bytes hex string
// return : verifyResult (true || false)
/**
* @deprecated need to update with proper signature verify function
* // TODO : this function needs to be updated with a proper with to verify the signature, once it's done, update testcases as well
*/
function verifySignature(message, signature, publicKey) {
return secp256k1.verify(typeConverter.hexStrToBuffer(message), typeConverter.hexStrToBuffer(signature), typeConverter.hexStrToBuffer(publicKey))
}
module.exports = {
derivePrivateKey,
derivePublicKey,
deriveP2PKHAddress,
deriveP2PKPubKey,
verifyAddress,
verifyP2PKPublicKey,
verifyPrivateKey,
signForSignature,
verifySignature
};