ccxt 4.5.18 → 4.5.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/dist/ccxt.browser.min.js +40 -16
- package/dist/cjs/_virtual/index.cjs.js +1459 -9
- package/dist/cjs/ccxt.js +8 -2
- package/dist/cjs/src/abstract/dydx.js +11 -0
- package/dist/cjs/src/base/Exchange.js +164 -10
- package/dist/cjs/src/base/ws/Client.js +3 -1
- package/dist/cjs/src/binance.js +8 -1
- package/dist/cjs/src/bingx.js +20 -0
- package/dist/cjs/src/bitget.js +43 -41
- package/dist/cjs/src/bybit.js +21 -23
- package/dist/cjs/src/deribit.js +6 -0
- package/dist/cjs/src/dydx.js +2454 -0
- package/dist/cjs/src/gate.js +4 -4
- package/dist/cjs/src/hibachi.js +1 -1
- package/dist/cjs/src/hyperliquid.js +207 -9
- package/dist/cjs/src/kucoin.js +711 -109
- package/dist/cjs/src/mexc.js +2 -3
- package/dist/cjs/src/pro/binance.js +59 -144
- package/dist/cjs/src/pro/dydx.js +418 -0
- package/dist/cjs/src/pro/kraken.js +4 -3
- package/dist/cjs/src/pro/xt.js +218 -4
- package/dist/cjs/src/protobuf/mexc/compiled.cjs.js +1 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/base/v1beta1/coin.js +56 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/v1beta1/multisig.js +56 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/crypto/secp256k1/keys.js +48 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/tx/signing/v1beta1/signing.js +343 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/tx/v1beta1/tx.js +717 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/accountplus/tx.js +60 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/clob_pair.js +45 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order.js +380 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order_removals.js +72 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/tx.js +211 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/transfer.js +195 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/tx.js +49 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/subaccount.js +57 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/google/protobuf/any.js +56 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/helpers.js +79 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/long/index.cjs.js +9 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/onboarding.js +59 -0
- package/dist/cjs/src/static_dependencies/dydx-v4-client/registry.js +39 -0
- package/dist/cjs/src/static_dependencies/noble-hashes/pbkdf2.js +69 -0
- package/dist/cjs/src/static_dependencies/noble-hashes/ripemd160.js +108 -0
- package/dist/cjs/src/static_dependencies/noble-hashes/utils.js +50 -1
- package/dist/cjs/src/static_dependencies/scure-base/index.js +29 -0
- package/dist/cjs/src/static_dependencies/scure-bip32/index.js +278 -0
- package/dist/cjs/src/static_dependencies/scure-bip39/index.js +97 -0
- package/dist/cjs/src/static_dependencies/scure-bip39/wordlists/english.js +2060 -0
- package/dist/cjs/src/static_dependencies/zklink/zklink-sdk-web.js +2 -0
- package/dist/cjs/src/toobit.js +2 -1
- package/js/ccxt.d.ts +8 -2
- package/js/ccxt.js +6 -2
- package/js/src/abstract/binance.d.ts +7 -0
- package/js/src/abstract/binancecoinm.d.ts +7 -0
- package/js/src/abstract/binanceus.d.ts +7 -0
- package/js/src/abstract/binanceusdm.d.ts +7 -0
- package/js/src/abstract/bitget.d.ts +1 -0
- package/js/src/abstract/dydx.d.ts +61 -0
- package/js/src/abstract/dydx.js +11 -0
- package/js/src/abstract/kucoin.d.ts +1 -1
- package/js/src/abstract/kucoinfutures.d.ts +1 -1
- package/js/src/base/Exchange.d.ts +7 -0
- package/js/src/base/Exchange.js +163 -10
- package/js/src/base/ws/Client.js +3 -1
- package/js/src/binance.js +8 -1
- package/js/src/bingx.js +20 -0
- package/js/src/bitget.d.ts +3 -3
- package/js/src/bitget.js +43 -41
- package/js/src/bybit.d.ts +3 -3
- package/js/src/bybit.js +21 -23
- package/js/src/deribit.js +6 -0
- package/js/src/dydx.d.ts +364 -0
- package/js/src/dydx.js +2453 -0
- package/js/src/gate.d.ts +2 -2
- package/js/src/gate.js +4 -4
- package/js/src/hibachi.js +1 -1
- package/js/src/hyperliquid.d.ts +17 -0
- package/js/src/hyperliquid.js +207 -9
- package/js/src/kucoin.d.ts +48 -1
- package/js/src/kucoin.js +711 -109
- package/js/src/mexc.js +2 -3
- package/js/src/pro/binance.d.ts +2 -2
- package/js/src/pro/binance.js +59 -144
- package/js/src/pro/dydx.d.ts +81 -0
- package/js/src/pro/dydx.js +417 -0
- package/js/src/pro/kraken.js +4 -3
- package/js/src/pro/xt.d.ts +85 -2
- package/js/src/pro/xt.js +218 -4
- package/js/src/static_dependencies/dydx-v4-client/cosmos/base/v1beta1/coin.d.ts +90 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/base/v1beta1/coin.js +163 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/keys.d.ts +26 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/keys.js +51 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/v1beta1/multisig.d.ts +48 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/v1beta1/multisig.js +85 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/secp256k1/keys.d.ts +40 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/secp256k1/keys.js +77 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/tx/signing/v1beta1/signing.d.ts +162 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/tx/signing/v1beta1/signing.js +329 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/tx/v1beta1/tx.d.ts +460 -0
- package/js/src/static_dependencies/dydx-v4-client/cosmos/tx/v1beta1/tx.js +698 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/accountplus/tx.d.ts +127 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/accountplus/tx.js +286 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/block_rate_limit_config.d.ts +66 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/block_rate_limit_config.js +109 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/clob_pair.d.ts +127 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/clob_pair.js +257 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/equity_tier_limit_config.d.ts +48 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/equity_tier_limit_config.js +93 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/finalize_block.d.ts +23 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/finalize_block.js +43 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/liquidations.d.ts +92 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/liquidations.js +164 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/liquidations_config.d.ts +124 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/liquidations_config.js +196 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/matches.d.ts +159 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/matches.js +324 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order.d.ts +546 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order.js +872 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order_removals.d.ts +84 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order_removals.js +181 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/tx.d.ts +397 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/tx.js +757 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/transfer.d.ts +120 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/transfer.js +246 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/tx.d.ts +79 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/tx.js +147 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/asset_position.d.ts +32 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/asset_position.js +59 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/perpetual_position.d.ts +34 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/perpetual_position.js +66 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/subaccount.d.ts +62 -0
- package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/subaccount.js +111 -0
- package/js/src/static_dependencies/dydx-v4-client/google/protobuf/any.d.ts +207 -0
- package/js/src/static_dependencies/dydx-v4-client/google/protobuf/any.js +50 -0
- package/js/src/static_dependencies/dydx-v4-client/helpers.d.ts +82 -0
- package/js/src/static_dependencies/dydx-v4-client/helpers.js +172 -0
- package/js/src/static_dependencies/dydx-v4-client/long/index.cjs +1473 -0
- package/js/src/static_dependencies/dydx-v4-client/long/index.d.cts +2 -0
- package/js/src/static_dependencies/dydx-v4-client/onboarding.d.ts +35 -0
- package/js/src/static_dependencies/dydx-v4-client/onboarding.js +56 -0
- package/js/src/static_dependencies/dydx-v4-client/registry.d.ts +7 -0
- package/js/src/static_dependencies/dydx-v4-client/registry.js +36 -0
- package/js/src/static_dependencies/noble-hashes/utils.d.ts +1 -0
- package/js/src/static_dependencies/noble-hashes/utils.js +4 -0
- package/js/src/static_dependencies/scure-bip32/index.d.ts +49 -0
- package/js/src/static_dependencies/scure-bip32/index.js +295 -0
- package/js/src/static_dependencies/scure-bip39/index.d.ts +54 -0
- package/js/src/static_dependencies/scure-bip39/index.js +140 -0
- package/js/src/static_dependencies/scure-bip39/wordlists/english.d.ts +1 -0
- package/js/src/static_dependencies/scure-bip39/wordlists/english.js +2054 -0
- package/js/src/toobit.js +2 -1
- package/package.json +9 -3
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var index$1 = require('../scure-bip32/index.js');
|
|
6
|
+
var index = require('../scure-bip39/index.js');
|
|
7
|
+
var english = require('../scure-bip39/wordlists/english.js');
|
|
8
|
+
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
10
|
+
/**
|
|
11
|
+
* @description Get Mnemonic and priv/pub keys from privateKeyBytes and BIP44 HD path
|
|
12
|
+
*
|
|
13
|
+
* @url https://github.com/confio/cosmos-hd-key-derivation-spec#bip44
|
|
14
|
+
*
|
|
15
|
+
* @param entropy used to generate mnemonic
|
|
16
|
+
*
|
|
17
|
+
* @param path BIP44 HD Path. Default is The Cosmos Hub path
|
|
18
|
+
*
|
|
19
|
+
* @throws Error if the hdkey does not exist
|
|
20
|
+
*
|
|
21
|
+
* @returns Mnemonic and priv/pub keys
|
|
22
|
+
*/
|
|
23
|
+
const exportMnemonicAndPrivateKey = (entropy, path = "m/44'/118'/0'/0/0") => {
|
|
24
|
+
const mnemonic = index.entropyToMnemonic(entropy, english.wordlist);
|
|
25
|
+
const { privateKey, publicKey } = deriveHDKeyFromMnemonic(mnemonic, path);
|
|
26
|
+
return {
|
|
27
|
+
mnemonic,
|
|
28
|
+
privateKey,
|
|
29
|
+
publicKey,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* @description Derive priv/pub keys from mnemonic and BIP44 HD path
|
|
34
|
+
*
|
|
35
|
+
* @url https://github.com/confio/cosmos-hd-key-derivation-spec#bip44
|
|
36
|
+
*
|
|
37
|
+
* @param mnemonic used to generate seed
|
|
38
|
+
*
|
|
39
|
+
* @param path BIP44 HD Path. Default is The Cosmos Hub path
|
|
40
|
+
*
|
|
41
|
+
* @throws Error if the hdkey does not exist
|
|
42
|
+
*
|
|
43
|
+
* @returns Priv/pub keys
|
|
44
|
+
*/
|
|
45
|
+
const deriveHDKeyFromMnemonic = (mnemonic, path = "m/44'/118'/0'/0/0") => {
|
|
46
|
+
const seed = index.mnemonicToSeedSync(mnemonic);
|
|
47
|
+
const hdkey = index$1.HDKey.fromMasterSeed(seed);
|
|
48
|
+
const derivedHdkey = hdkey.derive(path);
|
|
49
|
+
if (!hdkey.privateKey) {
|
|
50
|
+
throw new Error('null hd key');
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
privateKey: derivedHdkey.privateKey,
|
|
54
|
+
publicKey: derivedHdkey.publicKey,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
exports.deriveHDKeyFromMnemonic = deriveHDKeyFromMnemonic;
|
|
59
|
+
exports.exportMnemonicAndPrivateKey = exportMnemonicAndPrivateKey;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var keys = require('./cosmos/crypto/secp256k1/keys.js');
|
|
6
|
+
var tx$2 = require('./dydxprotocol/accountplus/tx.js');
|
|
7
|
+
var tx = require('./dydxprotocol/clob/tx.js');
|
|
8
|
+
var transfer = require('./dydxprotocol/sending/transfer.js');
|
|
9
|
+
var tx$1 = require('./dydxprotocol/sending/tx.js');
|
|
10
|
+
var any = require('./google/protobuf/any.js');
|
|
11
|
+
|
|
12
|
+
// ----------------------------------------------------------------------------
|
|
13
|
+
const registry = {
|
|
14
|
+
// clob
|
|
15
|
+
'/dydxprotocol.clob.MsgPlaceOrder': tx.MsgPlaceOrder,
|
|
16
|
+
'/dydxprotocol.clob.MsgCancelOrder': tx.MsgCancelOrder,
|
|
17
|
+
'/dydxprotocol.clob.MsgBatchCancel': tx.MsgBatchCancel,
|
|
18
|
+
// sending
|
|
19
|
+
'/dydxprotocol.sending.MsgCreateTransfer': tx$1.MsgCreateTransfer,
|
|
20
|
+
'/dydxprotocol.sending.MsgWithdrawFromSubaccount': transfer.MsgWithdrawFromSubaccount,
|
|
21
|
+
'/dydxprotocol.sending.MsgDepositToSubaccount': transfer.MsgDepositToSubaccount,
|
|
22
|
+
'/dydxprotocol.accountplus.TxExtension': tx$2.TxExtension,
|
|
23
|
+
'/cosmos.crypto.secp256k1.PubKey': keys.PubKey,
|
|
24
|
+
};
|
|
25
|
+
function encodeAsAny(encodeObject) {
|
|
26
|
+
const { typeUrl, value } = encodeObject;
|
|
27
|
+
const type = registry[typeUrl];
|
|
28
|
+
if (!type) {
|
|
29
|
+
throw new Error(`Unsupport type url: ${typeUrl}`);
|
|
30
|
+
}
|
|
31
|
+
const encodedMsg = type.encode(type.fromPartial(value)).finish();
|
|
32
|
+
return any.Any.fromPartial({
|
|
33
|
+
typeUrl: typeUrl,
|
|
34
|
+
value: encodedMsg,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
exports.encodeAsAny = encodeAsAny;
|
|
39
|
+
exports.registry = registry;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var _assert = require('./_assert.js');
|
|
6
|
+
var hmac = require('./hmac.js');
|
|
7
|
+
var utils = require('./utils.js');
|
|
8
|
+
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
10
|
+
// Common prologue and epilogue for sync/async functions
|
|
11
|
+
function pbkdf2Init(hash, _password, _salt, _opts) {
|
|
12
|
+
_assert["default"].hash(hash);
|
|
13
|
+
const opts = utils.checkOpts({ dkLen: 32, asyncTick: 10 }, _opts);
|
|
14
|
+
const { c, dkLen, asyncTick } = opts;
|
|
15
|
+
_assert["default"].number(c);
|
|
16
|
+
_assert["default"].number(dkLen);
|
|
17
|
+
_assert["default"].number(asyncTick);
|
|
18
|
+
if (c < 1)
|
|
19
|
+
throw new Error('PBKDF2: iterations (c) should be >= 1');
|
|
20
|
+
const password = utils.toBytes(_password);
|
|
21
|
+
const salt = utils.toBytes(_salt);
|
|
22
|
+
// DK = PBKDF2(PRF, Password, Salt, c, dkLen);
|
|
23
|
+
const DK = new Uint8Array(dkLen);
|
|
24
|
+
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
|
25
|
+
const PRF = hmac.hmac.create(hash, password);
|
|
26
|
+
const PRFSalt = PRF._cloneInto().update(salt);
|
|
27
|
+
return { c, dkLen, asyncTick, DK, PRF, PRFSalt };
|
|
28
|
+
}
|
|
29
|
+
function pbkdf2Output(PRF, PRFSalt, DK, prfW, u) {
|
|
30
|
+
PRF.destroy();
|
|
31
|
+
PRFSalt.destroy();
|
|
32
|
+
if (prfW)
|
|
33
|
+
prfW.destroy();
|
|
34
|
+
u.fill(0);
|
|
35
|
+
return DK;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* PBKDF2-HMAC: RFC 2898 key derivation function
|
|
39
|
+
* @param hash - hash function that would be used e.g. sha256
|
|
40
|
+
* @param password - password from which a derived key is generated
|
|
41
|
+
* @param salt - cryptographic salt
|
|
42
|
+
* @param opts - {c, dkLen} where c is work factor and dkLen is output message size
|
|
43
|
+
*/
|
|
44
|
+
function pbkdf2(hash, password, salt, opts) {
|
|
45
|
+
const { c, dkLen, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, opts);
|
|
46
|
+
let prfW; // Working copy
|
|
47
|
+
const arr = new Uint8Array(4);
|
|
48
|
+
const view = utils.createView(arr);
|
|
49
|
+
const u = new Uint8Array(PRF.outputLen);
|
|
50
|
+
// DK = T1 + T2 + ⋯ + Tdklen/hlen
|
|
51
|
+
for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
|
|
52
|
+
// Ti = F(Password, Salt, c, i)
|
|
53
|
+
const Ti = DK.subarray(pos, pos + PRF.outputLen);
|
|
54
|
+
view.setInt32(0, ti, false);
|
|
55
|
+
// F(Password, Salt, c, i) = U1 ^ U2 ^ ⋯ ^ Uc
|
|
56
|
+
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
|
57
|
+
(prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
|
|
58
|
+
Ti.set(u.subarray(0, Ti.length));
|
|
59
|
+
for (let ui = 1; ui < c; ui++) {
|
|
60
|
+
// Uc = PRF(Password, Uc−1)
|
|
61
|
+
PRF._cloneInto(prfW).update(u).digestInto(u);
|
|
62
|
+
for (let i = 0; i < Ti.length; i++)
|
|
63
|
+
Ti[i] ^= u[i];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
exports.pbkdf2 = pbkdf2;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var _sha2 = require('./_sha2.js');
|
|
6
|
+
var utils = require('./utils.js');
|
|
7
|
+
|
|
8
|
+
// ----------------------------------------------------------------------------
|
|
9
|
+
// https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
|
10
|
+
// https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf
|
|
11
|
+
const Rho = new Uint8Array([7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8]);
|
|
12
|
+
const Id = Uint8Array.from({ length: 16 }, (_, i) => i);
|
|
13
|
+
const Pi = Id.map((i) => (9 * i + 5) % 16);
|
|
14
|
+
let idxL = [Id];
|
|
15
|
+
let idxR = [Pi];
|
|
16
|
+
for (let i = 0; i < 4; i++)
|
|
17
|
+
for (let j of [idxL, idxR])
|
|
18
|
+
j.push(j[i].map((k) => Rho[k]));
|
|
19
|
+
const shifts = [
|
|
20
|
+
[11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
|
|
21
|
+
[12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7],
|
|
22
|
+
[13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9],
|
|
23
|
+
[14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6],
|
|
24
|
+
[15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5],
|
|
25
|
+
].map((i) => new Uint8Array(i));
|
|
26
|
+
const shiftsL = idxL.map((idx, i) => idx.map((j) => shifts[i][j]));
|
|
27
|
+
const shiftsR = idxR.map((idx, i) => idx.map((j) => shifts[i][j]));
|
|
28
|
+
const Kl = new Uint32Array([0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e]);
|
|
29
|
+
const Kr = new Uint32Array([0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000]);
|
|
30
|
+
// The rotate left (circular left shift) operation for uint32
|
|
31
|
+
const rotl = (word, shift) => (word << shift) | (word >>> (32 - shift));
|
|
32
|
+
// It's called f() in spec.
|
|
33
|
+
function f(group, x, y, z) {
|
|
34
|
+
if (group === 0)
|
|
35
|
+
return x ^ y ^ z;
|
|
36
|
+
else if (group === 1)
|
|
37
|
+
return (x & y) | (~x & z);
|
|
38
|
+
else if (group === 2)
|
|
39
|
+
return (x | ~y) ^ z;
|
|
40
|
+
else if (group === 3)
|
|
41
|
+
return (x & z) | (y & ~z);
|
|
42
|
+
else
|
|
43
|
+
return x ^ (y | ~z);
|
|
44
|
+
}
|
|
45
|
+
// Temporary buffer, not used to store anything between runs
|
|
46
|
+
const BUF = new Uint32Array(16);
|
|
47
|
+
class RIPEMD160 extends _sha2.SHA2 {
|
|
48
|
+
constructor() {
|
|
49
|
+
super(64, 20, 8, true);
|
|
50
|
+
this.h0 = 0x67452301 | 0;
|
|
51
|
+
this.h1 = 0xefcdab89 | 0;
|
|
52
|
+
this.h2 = 0x98badcfe | 0;
|
|
53
|
+
this.h3 = 0x10325476 | 0;
|
|
54
|
+
this.h4 = 0xc3d2e1f0 | 0;
|
|
55
|
+
}
|
|
56
|
+
get() {
|
|
57
|
+
const { h0, h1, h2, h3, h4 } = this;
|
|
58
|
+
return [h0, h1, h2, h3, h4];
|
|
59
|
+
}
|
|
60
|
+
set(h0, h1, h2, h3, h4) {
|
|
61
|
+
this.h0 = h0 | 0;
|
|
62
|
+
this.h1 = h1 | 0;
|
|
63
|
+
this.h2 = h2 | 0;
|
|
64
|
+
this.h3 = h3 | 0;
|
|
65
|
+
this.h4 = h4 | 0;
|
|
66
|
+
}
|
|
67
|
+
process(view, offset) {
|
|
68
|
+
for (let i = 0; i < 16; i++, offset += 4)
|
|
69
|
+
BUF[i] = view.getUint32(offset, true);
|
|
70
|
+
// prettier-ignore
|
|
71
|
+
let al = this.h0 | 0, ar = al, bl = this.h1 | 0, br = bl, cl = this.h2 | 0, cr = cl, dl = this.h3 | 0, dr = dl, el = this.h4 | 0, er = el;
|
|
72
|
+
// Instead of iterating 0 to 80, we split it into 5 groups
|
|
73
|
+
// And use the groups in constants, functions, etc. Much simpler
|
|
74
|
+
for (let group = 0; group < 5; group++) {
|
|
75
|
+
const rGroup = 4 - group;
|
|
76
|
+
const hbl = Kl[group], hbr = Kr[group]; // prettier-ignore
|
|
77
|
+
const rl = idxL[group], rr = idxR[group]; // prettier-ignore
|
|
78
|
+
const sl = shiftsL[group], sr = shiftsR[group]; // prettier-ignore
|
|
79
|
+
for (let i = 0; i < 16; i++) {
|
|
80
|
+
const tl = (rotl(al + f(group, bl, cl, dl) + BUF[rl[i]] + hbl, sl[i]) + el) | 0;
|
|
81
|
+
al = el, el = dl, dl = rotl(cl, 10) | 0, cl = bl, bl = tl; // prettier-ignore
|
|
82
|
+
}
|
|
83
|
+
// 2 loops are 10% faster
|
|
84
|
+
for (let i = 0; i < 16; i++) {
|
|
85
|
+
const tr = (rotl(ar + f(rGroup, br, cr, dr) + BUF[rr[i]] + hbr, sr[i]) + er) | 0;
|
|
86
|
+
ar = er, er = dr, dr = rotl(cr, 10) | 0, cr = br, br = tr; // prettier-ignore
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Add the compressed chunk to the current hash value
|
|
90
|
+
this.set((this.h1 + cl + dr) | 0, (this.h2 + dl + er) | 0, (this.h3 + el + ar) | 0, (this.h4 + al + br) | 0, (this.h0 + bl + cr) | 0);
|
|
91
|
+
}
|
|
92
|
+
roundClean() {
|
|
93
|
+
BUF.fill(0);
|
|
94
|
+
}
|
|
95
|
+
destroy() {
|
|
96
|
+
this.destroyed = true;
|
|
97
|
+
this.buffer.fill(0);
|
|
98
|
+
this.set(0, 0, 0, 0, 0);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* RIPEMD-160 - a hash function from 1990s.
|
|
103
|
+
* @param message - msg that would be hashed
|
|
104
|
+
*/
|
|
105
|
+
const ripemd160 = utils.wrapConstructor(() => new RIPEMD160());
|
|
106
|
+
|
|
107
|
+
exports.RIPEMD160 = RIPEMD160;
|
|
108
|
+
exports.ripemd160 = ripemd160;
|
|
@@ -15,7 +15,40 @@ const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
|
|
|
15
15
|
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
|
|
16
16
|
if (!isLE)
|
|
17
17
|
throw new Error('Non little-endian hardware is not supported');
|
|
18
|
-
Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
|
18
|
+
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
|
|
19
|
+
/**
|
|
20
|
+
* @example bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef])) // 'deadbeef'
|
|
21
|
+
*/
|
|
22
|
+
function bytesToHex(uint8a) {
|
|
23
|
+
// pre-caching improves the speed 6x
|
|
24
|
+
if (!(uint8a instanceof Uint8Array))
|
|
25
|
+
throw new Error('Uint8Array expected');
|
|
26
|
+
let hex = '';
|
|
27
|
+
for (let i = 0; i < uint8a.length; i++) {
|
|
28
|
+
hex += hexes[uint8a[i]];
|
|
29
|
+
}
|
|
30
|
+
return hex;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* @example hexToBytes('deadbeef') // Uint8Array.from([0xde, 0xad, 0xbe, 0xef])
|
|
34
|
+
*/
|
|
35
|
+
function hexToBytes(hex) {
|
|
36
|
+
if (typeof hex !== 'string') {
|
|
37
|
+
throw new TypeError('hexToBytes: expected string, got ' + typeof hex);
|
|
38
|
+
}
|
|
39
|
+
if (hex.length % 2)
|
|
40
|
+
throw new Error('hexToBytes: received invalid unpadded hex');
|
|
41
|
+
const array = new Uint8Array(hex.length / 2);
|
|
42
|
+
for (let i = 0; i < array.length; i++) {
|
|
43
|
+
const j = i * 2;
|
|
44
|
+
const hexByte = hex.slice(j, j + 2);
|
|
45
|
+
const byte = Number.parseInt(hexByte, 16);
|
|
46
|
+
if (Number.isNaN(byte) || byte < 0)
|
|
47
|
+
throw new Error('Invalid byte sequence');
|
|
48
|
+
array[i] = byte;
|
|
49
|
+
}
|
|
50
|
+
return array;
|
|
51
|
+
}
|
|
19
52
|
function utf8ToBytes(str) {
|
|
20
53
|
if (typeof str !== 'string') {
|
|
21
54
|
throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
|
|
@@ -54,6 +87,14 @@ class Hash {
|
|
|
54
87
|
return this._cloneInto();
|
|
55
88
|
}
|
|
56
89
|
}
|
|
90
|
+
// Check if object doens't have custom constructor (like Uint8Array/Array)
|
|
91
|
+
const isPlainObject = (obj) => Object.prototype.toString.call(obj) === '[object Object]' && obj.constructor === Object;
|
|
92
|
+
function checkOpts(defaults, opts) {
|
|
93
|
+
if (opts !== undefined && (typeof opts !== 'object' || !isPlainObject(opts)))
|
|
94
|
+
throw new TypeError('Options should be object or undefined');
|
|
95
|
+
const merged = Object.assign(defaults, opts);
|
|
96
|
+
return merged;
|
|
97
|
+
}
|
|
57
98
|
function wrapConstructor(hashConstructor) {
|
|
58
99
|
const hashC = (message) => hashConstructor().update(toBytes(message)).digest();
|
|
59
100
|
const tmp = hashConstructor();
|
|
@@ -79,10 +120,18 @@ function randomBytes(bytesLength = 32) {
|
|
|
79
120
|
}
|
|
80
121
|
throw new Error('crypto.getRandomValues must be defined');
|
|
81
122
|
}
|
|
123
|
+
const abytes = (b) => {
|
|
124
|
+
if (!(b instanceof Uint8Array || (ArrayBuffer.isView(b) && b.constructor.name === 'Uint8Array')))
|
|
125
|
+
throw new Error('Uint8Array expected');
|
|
126
|
+
};
|
|
82
127
|
|
|
83
128
|
exports.Hash = Hash;
|
|
129
|
+
exports.abytes = abytes;
|
|
130
|
+
exports.bytesToHex = bytesToHex;
|
|
131
|
+
exports.checkOpts = checkOpts;
|
|
84
132
|
exports.concatBytes = concatBytes;
|
|
85
133
|
exports.createView = createView;
|
|
134
|
+
exports.hexToBytes = hexToBytes;
|
|
86
135
|
exports.isLE = isLE;
|
|
87
136
|
exports.randomBytes = randomBytes;
|
|
88
137
|
exports.rotr = rotr;
|
|
@@ -242,6 +242,34 @@ function unsafeWrapper(fn) {
|
|
|
242
242
|
catch (e) { }
|
|
243
243
|
};
|
|
244
244
|
}
|
|
245
|
+
function checksum(len, fn) {
|
|
246
|
+
assertNumber(len);
|
|
247
|
+
if (typeof fn !== 'function')
|
|
248
|
+
throw new Error('checksum fn should be function');
|
|
249
|
+
return {
|
|
250
|
+
encode(data) {
|
|
251
|
+
if (!(data instanceof Uint8Array))
|
|
252
|
+
throw new Error('checksum.encode: input should be Uint8Array');
|
|
253
|
+
const checksum = fn(data).slice(0, len);
|
|
254
|
+
const res = new Uint8Array(data.length + len);
|
|
255
|
+
res.set(data);
|
|
256
|
+
res.set(checksum, data.length);
|
|
257
|
+
return res;
|
|
258
|
+
},
|
|
259
|
+
decode(data) {
|
|
260
|
+
if (!(data instanceof Uint8Array))
|
|
261
|
+
throw new Error('checksum.decode: input should be Uint8Array');
|
|
262
|
+
const payload = data.slice(0, -len);
|
|
263
|
+
const newChecksum = fn(payload).slice(0, len);
|
|
264
|
+
const oldChecksum = data.slice(-len);
|
|
265
|
+
for (let i = 0; i < len; i++)
|
|
266
|
+
if (newChecksum[i] !== oldChecksum[i])
|
|
267
|
+
throw new Error('Invalid checksum');
|
|
268
|
+
return payload;
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const utils = { alphabet, chain, checksum, radix, radix2, join, padding };
|
|
245
273
|
// RFC 4648 aka RFC 3548
|
|
246
274
|
// ---------------------
|
|
247
275
|
const base16 = chain(radix2(4), alphabet('0123456789abcdef'), join(''));
|
|
@@ -387,3 +415,4 @@ exports.base64 = base64;
|
|
|
387
415
|
exports.base64url = base64url;
|
|
388
416
|
exports.hex = hex;
|
|
389
417
|
exports.utf8 = utf8;
|
|
418
|
+
exports.utils = utils;
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var modular = require('../noble-curves/abstract/modular.js');
|
|
6
|
+
var secp256k1 = require('../noble-curves/secp256k1.js');
|
|
7
|
+
var hmac = require('../noble-hashes/hmac.js');
|
|
8
|
+
var ripemd160 = require('../noble-hashes/ripemd160.js');
|
|
9
|
+
var sha256 = require('../noble-hashes/sha256.js');
|
|
10
|
+
var sha512 = require('../noble-hashes/sha512.js');
|
|
11
|
+
var utils = require('../noble-hashes/utils.js');
|
|
12
|
+
var index = require('../scure-base/index.js');
|
|
13
|
+
|
|
14
|
+
// ----------------------------------------------------------------------------
|
|
15
|
+
const Point = secp256k1.secp256k1.ProjectivePoint;
|
|
16
|
+
function bytesToNumber(bytes) {
|
|
17
|
+
utils.abytes(bytes);
|
|
18
|
+
const h = bytes.length === 0 ? '0' : utils.bytesToHex(bytes);
|
|
19
|
+
return BigInt('0x' + h);
|
|
20
|
+
}
|
|
21
|
+
function numberToBytes(num) {
|
|
22
|
+
if (typeof num !== 'bigint')
|
|
23
|
+
throw new Error('bigint expected');
|
|
24
|
+
return utils.hexToBytes(num.toString(16).padStart(64, '0'));
|
|
25
|
+
}
|
|
26
|
+
const MASTER_SECRET = utils.utf8ToBytes('Bitcoin seed');
|
|
27
|
+
// Bitcoin hardcoded by default
|
|
28
|
+
const BITCOIN_VERSIONS = { private: 0x0488ade4, public: 0x0488b21e };
|
|
29
|
+
const HARDENED_OFFSET = 0x80000000;
|
|
30
|
+
const hash160 = (data) => ripemd160.ripemd160(sha256.sha256(data));
|
|
31
|
+
const fromU32 = (data) => utils.createView(data).getUint32(0, false);
|
|
32
|
+
const toU32 = (n) => {
|
|
33
|
+
if (!Number.isSafeInteger(n) || n < 0 || n > 2 ** 32 - 1) {
|
|
34
|
+
throw new Error('invalid number, should be from 0 to 2**32-1, got ' + n);
|
|
35
|
+
}
|
|
36
|
+
const buf = new Uint8Array(4);
|
|
37
|
+
utils.createView(buf).setUint32(0, n, false);
|
|
38
|
+
return buf;
|
|
39
|
+
};
|
|
40
|
+
class HDKey {
|
|
41
|
+
constructor(opt) {
|
|
42
|
+
this.depth = 0;
|
|
43
|
+
this.index = 0;
|
|
44
|
+
this.chainCode = null;
|
|
45
|
+
this.parentFingerprint = 0;
|
|
46
|
+
if (!opt || typeof opt !== 'object') {
|
|
47
|
+
throw new Error('HDKey.constructor must not be called directly');
|
|
48
|
+
}
|
|
49
|
+
this.versions = opt.versions || BITCOIN_VERSIONS;
|
|
50
|
+
this.depth = opt.depth || 0;
|
|
51
|
+
this.chainCode = opt.chainCode || null;
|
|
52
|
+
this.index = opt.index || 0;
|
|
53
|
+
this.parentFingerprint = opt.parentFingerprint || 0;
|
|
54
|
+
if (!this.depth) {
|
|
55
|
+
if (this.parentFingerprint || this.index) {
|
|
56
|
+
throw new Error('HDKey: zero depth with non-zero index/parent fingerprint');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (opt.publicKey && opt.privateKey) {
|
|
60
|
+
throw new Error('HDKey: publicKey and privateKey at same time.');
|
|
61
|
+
}
|
|
62
|
+
if (opt.privateKey) {
|
|
63
|
+
if (!secp256k1.secp256k1.utils.isValidPrivateKey(opt.privateKey)) {
|
|
64
|
+
throw new Error('Invalid private key');
|
|
65
|
+
}
|
|
66
|
+
this.privKey =
|
|
67
|
+
typeof opt.privateKey === 'bigint' ? opt.privateKey : bytesToNumber(opt.privateKey);
|
|
68
|
+
this.privKeyBytes = numberToBytes(this.privKey);
|
|
69
|
+
this.pubKey = secp256k1.secp256k1.getPublicKey(opt.privateKey, true);
|
|
70
|
+
}
|
|
71
|
+
else if (opt.publicKey) {
|
|
72
|
+
this.pubKey = Point.fromHex(opt.publicKey).toRawBytes(true); // force compressed point
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
throw new Error('HDKey: no public or private key provided');
|
|
76
|
+
}
|
|
77
|
+
this.pubHash = hash160(this.pubKey);
|
|
78
|
+
}
|
|
79
|
+
get fingerprint() {
|
|
80
|
+
if (!this.pubHash) {
|
|
81
|
+
throw new Error('No publicKey set!');
|
|
82
|
+
}
|
|
83
|
+
return fromU32(this.pubHash);
|
|
84
|
+
}
|
|
85
|
+
get identifier() {
|
|
86
|
+
return this.pubHash;
|
|
87
|
+
}
|
|
88
|
+
get pubKeyHash() {
|
|
89
|
+
return this.pubHash;
|
|
90
|
+
}
|
|
91
|
+
get privateKey() {
|
|
92
|
+
return this.privKeyBytes || null;
|
|
93
|
+
}
|
|
94
|
+
get publicKey() {
|
|
95
|
+
return this.pubKey || null;
|
|
96
|
+
}
|
|
97
|
+
get privateExtendedKey() {
|
|
98
|
+
const priv = this.privateKey;
|
|
99
|
+
if (!priv) {
|
|
100
|
+
throw new Error('No private key');
|
|
101
|
+
}
|
|
102
|
+
return index.base58.encode(this.serialize(this.versions.private, utils.concatBytes(new Uint8Array([0]), priv)));
|
|
103
|
+
}
|
|
104
|
+
get publicExtendedKey() {
|
|
105
|
+
if (!this.pubKey) {
|
|
106
|
+
throw new Error('No public key');
|
|
107
|
+
}
|
|
108
|
+
return index.base58.encode(this.serialize(this.versions.public, this.pubKey));
|
|
109
|
+
}
|
|
110
|
+
static fromMasterSeed(seed, versions = BITCOIN_VERSIONS) {
|
|
111
|
+
utils.abytes(seed);
|
|
112
|
+
if (8 * seed.length < 128 || 8 * seed.length > 512) {
|
|
113
|
+
throw new Error('HDKey: seed length must be between 128 and 512 bits; 256 bits is advised, got ' +
|
|
114
|
+
seed.length);
|
|
115
|
+
}
|
|
116
|
+
const I = hmac.hmac(sha512.sha512, MASTER_SECRET, seed);
|
|
117
|
+
return new HDKey({
|
|
118
|
+
versions,
|
|
119
|
+
chainCode: I.slice(32),
|
|
120
|
+
privateKey: I.slice(0, 32),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
static fromExtendedKey(base58key, versions = BITCOIN_VERSIONS) {
|
|
124
|
+
// => version(4) || depth(1) || fingerprint(4) || index(4) || chain(32) || key(33)
|
|
125
|
+
const keyBuffer = index.base58.decode(base58key);
|
|
126
|
+
const keyView = utils.createView(keyBuffer);
|
|
127
|
+
const version = keyView.getUint32(0, false);
|
|
128
|
+
const opt = {
|
|
129
|
+
versions,
|
|
130
|
+
depth: keyBuffer[4],
|
|
131
|
+
parentFingerprint: keyView.getUint32(5, false),
|
|
132
|
+
index: keyView.getUint32(9, false),
|
|
133
|
+
chainCode: keyBuffer.slice(13, 45),
|
|
134
|
+
};
|
|
135
|
+
const key = keyBuffer.slice(45);
|
|
136
|
+
const isPriv = key[0] === 0;
|
|
137
|
+
if (version !== versions[isPriv ? 'private' : 'public']) {
|
|
138
|
+
throw new Error('Version mismatch');
|
|
139
|
+
}
|
|
140
|
+
if (isPriv) {
|
|
141
|
+
return new HDKey({ ...opt, privateKey: key.slice(1) });
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
return new HDKey({ ...opt, publicKey: key });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
static fromJSON(json) {
|
|
148
|
+
return HDKey.fromExtendedKey(json.xpriv);
|
|
149
|
+
}
|
|
150
|
+
derive(path) {
|
|
151
|
+
if (!/^[mM]'?/.test(path)) {
|
|
152
|
+
throw new Error('Path must start with "m" or "M"');
|
|
153
|
+
}
|
|
154
|
+
if (/^[mM]'?$/.test(path)) {
|
|
155
|
+
return this;
|
|
156
|
+
}
|
|
157
|
+
const parts = path.replace(/^[mM]'?\//, '').split('/');
|
|
158
|
+
// tslint:disable-next-line
|
|
159
|
+
let child = this;
|
|
160
|
+
for (const c of parts) {
|
|
161
|
+
const m = /^(\d+)('?)$/.exec(c);
|
|
162
|
+
const m1 = m && m[1];
|
|
163
|
+
if (!m || m.length !== 3 || typeof m1 !== 'string')
|
|
164
|
+
throw new Error('invalid child index: ' + c);
|
|
165
|
+
let idx = +m1;
|
|
166
|
+
if (!Number.isSafeInteger(idx) || idx >= HARDENED_OFFSET) {
|
|
167
|
+
throw new Error('Invalid index');
|
|
168
|
+
}
|
|
169
|
+
// hardened key
|
|
170
|
+
if (m[2] === "'") {
|
|
171
|
+
idx += HARDENED_OFFSET;
|
|
172
|
+
}
|
|
173
|
+
child = child.deriveChild(idx);
|
|
174
|
+
}
|
|
175
|
+
return child;
|
|
176
|
+
}
|
|
177
|
+
deriveChild(index) {
|
|
178
|
+
if (!this.pubKey || !this.chainCode) {
|
|
179
|
+
throw new Error('No publicKey or chainCode set');
|
|
180
|
+
}
|
|
181
|
+
let data = toU32(index);
|
|
182
|
+
if (index >= HARDENED_OFFSET) {
|
|
183
|
+
// Hardened
|
|
184
|
+
const priv = this.privateKey;
|
|
185
|
+
if (!priv) {
|
|
186
|
+
throw new Error('Could not derive hardened child key');
|
|
187
|
+
}
|
|
188
|
+
// Hardened child: 0x00 || ser256(kpar) || ser32(index)
|
|
189
|
+
data = utils.concatBytes(new Uint8Array([0]), priv, data);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// Normal child: serP(point(kpar)) || ser32(index)
|
|
193
|
+
data = utils.concatBytes(this.pubKey, data);
|
|
194
|
+
}
|
|
195
|
+
const I = hmac.hmac(sha512.sha512, this.chainCode, data);
|
|
196
|
+
const childTweak = bytesToNumber(I.slice(0, 32));
|
|
197
|
+
const chainCode = I.slice(32);
|
|
198
|
+
if (!secp256k1.secp256k1.utils.isValidPrivateKey(childTweak)) {
|
|
199
|
+
throw new Error('Tweak bigger than curve order');
|
|
200
|
+
}
|
|
201
|
+
const opt = {
|
|
202
|
+
versions: this.versions,
|
|
203
|
+
chainCode,
|
|
204
|
+
depth: this.depth + 1,
|
|
205
|
+
parentFingerprint: this.fingerprint,
|
|
206
|
+
index,
|
|
207
|
+
};
|
|
208
|
+
try {
|
|
209
|
+
// Private parent key -> private child key
|
|
210
|
+
if (this.privateKey) {
|
|
211
|
+
const added = modular.mod(this.privKey + childTweak, secp256k1.secp256k1.CURVE.n);
|
|
212
|
+
if (!secp256k1.secp256k1.utils.isValidPrivateKey(added)) {
|
|
213
|
+
throw new Error('The tweak was out of range or the resulted private key is invalid');
|
|
214
|
+
}
|
|
215
|
+
opt.privateKey = added;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const added = Point.fromHex(this.pubKey).add(Point.fromPrivateKey(childTweak));
|
|
219
|
+
// Cryptographically impossible: hmac-sha512 preimage would need to be found
|
|
220
|
+
if (added.equals(Point.ZERO)) {
|
|
221
|
+
throw new Error('The tweak was equal to negative P, which made the result key invalid');
|
|
222
|
+
}
|
|
223
|
+
opt.publicKey = added.toRawBytes(true);
|
|
224
|
+
}
|
|
225
|
+
return new HDKey(opt);
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
return this.deriveChild(index + 1);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
sign(hash) {
|
|
232
|
+
if (!this.privateKey) {
|
|
233
|
+
throw new Error('No privateKey set!');
|
|
234
|
+
}
|
|
235
|
+
utils.abytes(hash);
|
|
236
|
+
return secp256k1.secp256k1.sign(hash, this.privKey).toCompactRawBytes();
|
|
237
|
+
}
|
|
238
|
+
verify(hash, signature) {
|
|
239
|
+
utils.abytes(hash);
|
|
240
|
+
utils.abytes(signature);
|
|
241
|
+
if (!this.publicKey) {
|
|
242
|
+
throw new Error('No publicKey set!');
|
|
243
|
+
}
|
|
244
|
+
let sig;
|
|
245
|
+
try {
|
|
246
|
+
sig = secp256k1.secp256k1.Signature.fromCompact(signature);
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
return secp256k1.secp256k1.verify(sig, hash, this.publicKey);
|
|
252
|
+
}
|
|
253
|
+
wipePrivateData() {
|
|
254
|
+
this.privKey = undefined;
|
|
255
|
+
if (this.privKeyBytes) {
|
|
256
|
+
this.privKeyBytes.fill(0);
|
|
257
|
+
this.privKeyBytes = undefined;
|
|
258
|
+
}
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
toJSON() {
|
|
262
|
+
return {
|
|
263
|
+
xpriv: this.privateExtendedKey,
|
|
264
|
+
xpub: this.publicExtendedKey,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
serialize(version, key) {
|
|
268
|
+
if (!this.chainCode) {
|
|
269
|
+
throw new Error('No chainCode set');
|
|
270
|
+
}
|
|
271
|
+
utils.abytes(key);
|
|
272
|
+
// version(4) || depth(1) || fingerprint(4) || index(4) || chain(32) || key(33)
|
|
273
|
+
return utils.concatBytes(toU32(version), new Uint8Array([this.depth]), toU32(this.parentFingerprint), toU32(this.index), this.chainCode, key);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
exports.HARDENED_OFFSET = HARDENED_OFFSET;
|
|
278
|
+
exports.HDKey = HDKey;
|