删掉所有 option 参数,换用具体的 {...}
This commit is contained in:
parent
8780cd1c40
commit
8873cd8884
169
index.js
169
index.js
@ -17,11 +17,11 @@ const secp256k1 = require('secp256k1')
|
|||||||
|
|
||||||
const my = {}
|
const my = {}
|
||||||
my.HASHER = 'sha256' // 默认的哈希算法。could be md5, sha1, sha256, sha512, ripemd160 and much more。 可用 Crypto.getHashes/Ciphers/Curves() 查看支持的种类。
|
my.HASHER = 'sha256' // 默认的哈希算法。could be md5, sha1, sha256, sha512, ripemd160 and much more。 可用 Crypto.getHashes/Ciphers/Curves() 查看支持的种类。
|
||||||
my.HASHER_LIST = crypto.getHashes()
|
my.HASHER_LIST = typeof crypto.getHashes === 'function' ? crypto.getHashes() : [my.HASHER]
|
||||||
my.CIPHER = 'aes-256-cfb' // 默认的加解密算法
|
my.CIPHER = 'aes-256-cfb' // 默认的加解密算法
|
||||||
my.CIPHER_LIST = crypto.getCiphers()
|
my.CIPHER_LIST = typeof crypto.getCiphers === 'function' ? crypto.getCiphers() : [my.CIPHER]
|
||||||
my.CURVE = 'secp256k1' // 默认的ECDH曲线,用于把私钥转成公钥。
|
my.CURVE = 'secp256k1' // 默认的ECDH曲线,用于把私钥转成公钥。
|
||||||
my.CURVE_LIST = ['secp256k1'] // crypto.getCurves() 引入到浏览器里后出错,不支持 getCurves.
|
my.CURVE_LIST = typeof crypto.getCurves === 'function' ? crypto.getCurves() : [my.CURVE] // crypto.getCurves() 引入到浏览器里后出错,不支持 getCurves.
|
||||||
my.OUTPUT = 'hex' // 默认的哈希或加密的输入格式
|
my.OUTPUT = 'hex' // 默认的哈希或加密的输入格式
|
||||||
my.OUTPUT_LIST = ['hex', 'latin1', 'base64'] // or 'buf' to Buffer explicitly
|
my.OUTPUT_LIST = ['hex', 'latin1', 'base64'] // or 'buf' to Buffer explicitly
|
||||||
my.INPUT = 'utf8' // 默认的加密方法的明文格式。utf8 能够兼容 latin1, ascii 的情形
|
my.INPUT = 'utf8' // 默认的加密方法的明文格式。utf8 能够兼容 latin1, ascii 的情形
|
||||||
@ -30,7 +30,6 @@ my.COIN = 'TIC' // 默认的币种
|
|||||||
my.COIN_LIST = ['TIC', 'BTC', 'ETH']
|
my.COIN_LIST = ['TIC', 'BTC', 'ETH']
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* @class TICrypto
|
* @class TICrypto
|
||||||
*/
|
*/
|
||||||
@ -160,8 +159,8 @@ class TICrypto {
|
|||||||
if (this.isHashable(data)) {
|
if (this.isHashable(data)) {
|
||||||
if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data)
|
if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data)
|
||||||
if (salt && typeof salt === 'string') data = data + this.hash(salt)
|
if (salt && typeof salt === 'string') data = data + this.hash(salt)
|
||||||
let inputEncoding = input // my.INPUT_LIST.indexOf(option.input)>=0?option.input:my.INPUT // 'utf8', 'ascii' or 'latin1' for string data, default to utf8 if not specified; ignored for Buffer, TypedArray, or DataView.
|
let inputEncoding = input // my.INPUT_LIST.indexOf(input)>=0?input:my.INPUT // 'utf8', 'ascii' or 'latin1' for string data, default to utf8 if not specified; ignored for Buffer, TypedArray, or DataView.
|
||||||
let outputEncoding = output === 'buf' ? undefined : output // (my.OUTPUT_LIST.indexOf(output)>=0?output:my.OUTPUT) // option.output: 留空=》默认输出hex格式;或者手动指定 'buf', hex', 'latin1' or 'base64'
|
let outputEncoding = output === 'buf' ? undefined : output // (my.OUTPUT_LIST.indexOf(output)>=0?output:my.OUTPUT) // output: 留空=》默认输出hex格式;或者手动指定 'buf', hex', 'latin1' or 'base64'
|
||||||
return crypto.createHash(hasher).update(data, inputEncoding).digest(outputEncoding)
|
return crypto.createHash(hasher).update(data, inputEncoding).digest(outputEncoding)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -280,9 +279,11 @@ class TICrypto {
|
|||||||
} else if (seckey.length === 64) {
|
} else if (seckey.length === 64) {
|
||||||
// 纯 crypto
|
// 纯 crypto
|
||||||
let seckeyPEM = await new keyman.Key('oct', this.hex2buf(seckey), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
|
let seckeyPEM = await new keyman.Key('oct', this.hex2buf(seckey), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
|
||||||
let signer = crypto.createSign(['sha1', 'sha256', 'sha512'].indexOf(hasher) >= 0 ? hasher : my.HASHER)
|
// let signer = crypto.createSign(my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER) // 注意,不知为何,hasher必须含有'sha'才能完成签名,例如 sha1, sha256, sha512, sha3, RSA-SHA1, id-rsassa-pkcs1-v1_5-with-sha3-224, 其他都会报错。
|
||||||
signer.update(this.hash(data)).end()
|
// signer.update(this.hash(data)).end()
|
||||||
let signature = signer.sign(seckeyPEM, 'hex')
|
// let signature = signer.sign(seckeyPEM, 'hex')
|
||||||
|
// since nodejs 12, 有了 crypto.sign 方法:
|
||||||
|
let signature = crypto.sign(my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER, Buffer.from(this.hash(data)), seckeyPEM).toString('hex')
|
||||||
return signature // 发现同样的输入,nodejs里每次调用会生成不同的 signature, 且长度不定(140,142,144 hex) 但都可以通过 verify。但在浏览器里调用,signature却是固定的。
|
return signature // 发现同样的输入,nodejs里每次调用会生成不同的 signature, 且长度不定(140,142,144 hex) 但都可以通过 verify。但在浏览器里调用,signature却是固定的。
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +311,7 @@ class TICrypto {
|
|||||||
let verified = nacl.sign.detached.verify(bufHash, bufSignature, bufPubkey)
|
let verified = nacl.sign.detached.verify(bufHash, bufSignature, bufPubkey)
|
||||||
return verified
|
return verified
|
||||||
} else if ('eccrypto' === tool && signature.length >= 140) {
|
} else if ('eccrypto' === tool && signature.length >= 140) {
|
||||||
// 默认使用 eccrypto
|
// 默认使用 eccrypto // 发现大小写不影响 eccrypto 验签!都能通过
|
||||||
try {
|
try {
|
||||||
let result = await eccrypto.verify(Buffer.from(pubkey, 'hex'), this.hash(data, { output: 'buf' }), Buffer.from(signature, 'hex')) // 如果给signature添加1位hex,eccrypto 的 verify结果也是true! 估计因为一位hex不被转成字节。
|
let result = await eccrypto.verify(Buffer.from(pubkey, 'hex'), this.hash(data, { output: 'buf' }), Buffer.from(signature, 'hex')) // 如果给signature添加1位hex,eccrypto 的 verify结果也是true! 估计因为一位hex不被转成字节。
|
||||||
return true
|
return true
|
||||||
@ -319,11 +320,18 @@ class TICrypto {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else if (signature.length >= 140) {
|
} else if (signature.length >= 140) {
|
||||||
// 纯 crypto
|
// 纯 crypto // 发现大小写不影响 crypto 验签!都能通过
|
||||||
let pubkeyPEM = await new keyman.Key('oct', this.hex2buf(pubkey), { namedCurve: 'P-256K' }).export('pem') // 公钥导出的der格式为88字节。经测试,同一对压缩和非压缩公钥得出的结果一模一样。
|
let pubkeyPEM = await new keyman.Key('oct', this.hex2buf(pubkey), { namedCurve: 'P-256K' }).export('pem') // 公钥导出的der格式为88字节。经测试,同一对压缩和非压缩公钥得出的结果一模一样。
|
||||||
let verifier = crypto.createVerify(['sha1', 'sha256', 'sha512'].indexOf(hasher) >= 0 ? hasher : my.HASHER)
|
// let verifier = crypto.createVerify(my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER)
|
||||||
verifier.update(this.hash(data)).end() // end() 在 nodejs 12 里返回verifier自身,但在浏览器里返回 undefined,因此不能串联运行。
|
// verifier.update(this.hash(data)).end() // end() 在 nodejs 12 里返回verifier自身,但在浏览器里返回 undefined,因此不能串联运行。
|
||||||
let verified = verifier.verify(pubkeyPEM, signature, 'hex') // 如果给signature添加1位hex,crypto 的 verify结果也是true! 估计因为一位hex不被转成字节。但减少1位会导致false
|
// let verified = verifier.verify(pubkeyPEM, signature, 'hex') // 如果给signature添加1位hex,crypto 的 verify结果也是true! 估计因为一位hex不被转成字节。但减少1位会导致false
|
||||||
|
// since nodejs 12, 有了 crypto.verify 方法:
|
||||||
|
let verified = crypto.verify(
|
||||||
|
my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER,
|
||||||
|
Buffer.from(this.hash(data)),
|
||||||
|
pubkeyPEM,
|
||||||
|
Buffer.from(signature, 'hex')
|
||||||
|
)
|
||||||
return verified
|
return verified
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,12 +347,11 @@ class TICrypto {
|
|||||||
* @return {Object} {pubkey, seckey, address,}
|
* @return {Object} {pubkey, seckey, address,}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static pass2keypair(pass, option) {
|
static pass2keypair(pass, { hasher } = {}) {
|
||||||
// 如果使用其他机制,例如密码、随机数,不使用secword,也可生成keypair
|
// 如果使用其他机制,例如密码、随机数,不使用secword,也可生成keypair
|
||||||
if (this.isHashable(pass)) {
|
if (this.isHashable(pass)) {
|
||||||
option = option || {}
|
hasher = my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER
|
||||||
option.hasher = my.HASHER_LIST.indexOf(option.hasher) >= 0 ? option.hasher : my.HASHER
|
var hashBuf = crypto.createHash(hasher).update(pass).digest()
|
||||||
var hashBuf = crypto.createHash(option.hasher).update(pass).digest()
|
|
||||||
var keypair = nacl.sign.keyPair.fromSeed(hashBuf) // nacl的seed要求是32字节
|
var keypair = nacl.sign.keyPair.fromSeed(hashBuf) // nacl的seed要求是32字节
|
||||||
return {
|
return {
|
||||||
hash: hashBuf.toString('hex'),
|
hash: hashBuf.toString('hex'),
|
||||||
@ -390,10 +397,10 @@ class TICrypto {
|
|||||||
* @return {Object} {pubkey, seckey,}
|
* @return {Object} {pubkey, seckey,}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static secword2keypair(secword, option) {
|
static secword2keypair(secword, { coin, pass, path, tool, hasher } = {}) {
|
||||||
// option.coin 币种;
|
// coin 币种;
|
||||||
// option.passphase 密码,默认为空;
|
// passphase 密码,默认为空;
|
||||||
// option.path==='master' 生成 HD master key,不定义则默认为相应币种的第一对公私钥。
|
// path==='master' 生成 HD master key,不定义则默认为相应币种的第一对公私钥。
|
||||||
// path 规范为 m/Purpose'/CoinType'/Account'/Change/Index (https://learnblockchain.cn/2018/09/28/hdwallet/), 其中
|
// path 规范为 m/Purpose'/CoinType'/Account'/Change/Index (https://learnblockchain.cn/2018/09/28/hdwallet/), 其中
|
||||||
// Purpose===44 for BIP44,
|
// Purpose===44 for BIP44,
|
||||||
// CoinType===0 for BTC, 60 for ETH. (https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
|
// CoinType===0 for BTC, 60 for ETH. (https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
|
||||||
@ -402,30 +409,28 @@ class TICrypto {
|
|||||||
// 据测试, Purpose和CoinType都可以任意其他值,不必要如规范所示;' 引号可有可无,导致的密钥不一样;
|
// 据测试, Purpose和CoinType都可以任意其他值,不必要如规范所示;' 引号可有可无,导致的密钥不一样;
|
||||||
// Account 最大为 0x7FFFFFFF, Change/Index 最大均为 0xFFFFFFFF(=4294967295)
|
// Account 最大为 0x7FFFFFFF, Change/Index 最大均为 0xFFFFFFFF(=4294967295)
|
||||||
// 但可以不断延伸下去:/xxx/xxx/xxx/xxx/...
|
// 但可以不断延伸下去:/xxx/xxx/xxx/xxx/...
|
||||||
option = option || {}
|
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
if (option.coin) option.coin = option.coin.toUpperCase()
|
|
||||||
option.coin = my.COIN_LIST.indexOf(option.coin) >= 0 ? option.coin : my.COIN
|
|
||||||
|
|
||||||
if (option.tool === 'nacl') {
|
if (tool === 'nacl') {
|
||||||
// 采用自己的算法:bip39算法从secword到种子,hash后用 nacl.sign.keyPair.fromSeed()方法。
|
// 采用自己的算法:bip39算法从secword到种子,hash后用 nacl.sign.keyPair.fromSeed()方法。
|
||||||
option.hasher = my.HASHER_LIST.indexOf(option.hasher) >= 0 ? option.hasher : my.HASHER
|
hasher = my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER
|
||||||
let hashBuf = crypto.createHash(option.hasher).update(this.secword2seed(secword, option.pass)).digest()
|
let hashBuf = crypto.createHash(hasher).update(this.secword2seed(secword, pass)).digest()
|
||||||
let keypair = nacl.sign.keyPair.fromSeed(hashBuf) // nacl.sign.keyPair.fromSeed 要求32字节的种子,而 this.secword2seed生成的是64字节种子,所以要先做一次sha256
|
let keypair = nacl.sign.keyPair.fromSeed(hashBuf) // nacl.sign.keyPair.fromSeed 要求32字节的种子,而 this.secword2seed生成的是64字节种子,所以要先做一次sha256
|
||||||
return {
|
return {
|
||||||
coin: option.coin,
|
coin: coin,
|
||||||
secword: secword,
|
secword: secword,
|
||||||
pubkey: Buffer.from(keypair.publicKey).toString('hex'), // 测试过 不能直接keypair.publicKey.toString('hex'),不是buffer类型
|
pubkey: Buffer.from(keypair.publicKey).toString('hex'), // 测试过 不能直接keypair.publicKey.toString('hex'),不是buffer类型
|
||||||
seckey: Buffer.from(keypair.secretKey).toString('hex'), // nacl.sign.keyPair.fromSeed 得到的 seckey 是64字节的,不同于比特币/以太坊的32字节密钥。
|
seckey: Buffer.from(keypair.secretKey).toString('hex'), // nacl.sign.keyPair.fromSeed 得到的 seckey 是64字节的,不同于比特币/以太坊的32字节密钥。
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 用 bip39 算法从 secword 到种子,再用 bip32 算法从种子到根私钥。这是比特币、以太坊的标准方式,结果一致。
|
// 用 bip39 算法从 secword 到种子,再用 bip32 算法从种子到根私钥。这是比特币、以太坊的标准方式,结果一致。
|
||||||
let hdmaster = hdkey.fromMasterSeed(Buffer.from(this.secword2seed(secword, option.pass), 'hex')) // 和 new BitcoreMnemonic(secword).toHDPrivateKey 求出的公私钥一样!
|
let hdmaster = hdkey.fromMasterSeed(Buffer.from(this.secword2seed(secword, pass), 'hex')) // 和 new BitcoreMnemonic(secword).toHDPrivateKey 求出的公私钥一样!
|
||||||
// let hdmaster=new BitcoreMnemonic(secword).toHDPrivateKey(option.pass) // 和 ethers.HDNode.fromMnemonic(secword)的公私钥一样。而 ethers.HDNode.fromMnemonic(secword).derivePath("m/44'/60'/0'/0/0")的公私钥===ethers.Wallet.fromMnemonic(secword [,"m/44'/60'/0'/0/0"])
|
// let hdmaster=new BitcoreMnemonic(secword).toHDPrivateKey(pass) // 和 ethers.HDNode.fromMnemonic(secword)的公私钥一样。而 ethers.HDNode.fromMnemonic(secword).derivePath("m/44'/60'/0'/0/0")的公私钥===ethers.Wallet.fromMnemonic(secword [,"m/44'/60'/0'/0/0"])
|
||||||
let key = hdmaster
|
let key = hdmaster
|
||||||
if (option.path === 'master') {
|
if (path === 'master') {
|
||||||
key = hdmaster
|
key = hdmaster
|
||||||
} else if (!option.path) {
|
} else if (!path) {
|
||||||
switch (option.coin) {
|
switch (coin) {
|
||||||
case 'BTC':
|
case 'BTC':
|
||||||
key = hdmaster.derive("m/44'/0'/0'/0/0")
|
key = hdmaster.derive("m/44'/0'/0'/0/0")
|
||||||
break
|
break
|
||||||
@ -438,11 +443,11 @@ class TICrypto {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 指定了路径 option.path,例如 "m/44'/0'/0'/0/6" 或 "m/0/2147483647'/1"
|
// 指定了路径 path,例如 "m/44'/0'/0'/0/6" 或 "m/0/2147483647'/1"
|
||||||
key = hdmaster.derive(option.path)
|
key = hdmaster.derive(path)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
coin: option.coin,
|
coin: coin,
|
||||||
secword: secword,
|
secword: secword,
|
||||||
seckey: key.privateKey.toString('hex'), // 或者 key.toJSON().privateKey。或者 key.privateKey.slice(2) 删除开头的'0x'如果是ethers.HDNode.fromMnemonic(secword)的结果
|
seckey: key.privateKey.toString('hex'), // 或者 key.toJSON().privateKey。或者 key.privateKey.slice(2) 删除开头的'0x'如果是ethers.HDNode.fromMnemonic(secword)的结果
|
||||||
pubkey: key.publicKey.toString('hex'),
|
pubkey: key.publicKey.toString('hex'),
|
||||||
@ -493,18 +498,16 @@ class TICrypto {
|
|||||||
* @return {Object}
|
* @return {Object}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static secword2account(secword, option) {
|
static secword2account(secword, { coin, pass, path, tool, hasher } = {}) {
|
||||||
// account 比 keypair 多了 address 字段。
|
// account 比 keypair 多了 address 字段。
|
||||||
option = option || {}
|
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
if (option.coin) option.coin = option.coin.toUpperCase()
|
let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher })
|
||||||
option.coin = my.COIN_LIST.indexOf(option.coin) >= 0 ? option.coin : my.COIN
|
|
||||||
let kp = this.secword2keypair(secword, option)
|
|
||||||
if (kp) {
|
if (kp) {
|
||||||
if (option.coin === 'ETH') {
|
if (coin === 'ETH') {
|
||||||
let uncompressedPubkey = this.decompressPubkey(kp.pubkey)
|
let uncompressedPubkey = this.decompressPubkey(kp.pubkey)
|
||||||
kp.address = this.pubkey2address(uncompressedPubkey, { coin: 'ETH' })
|
kp.address = this.pubkey2address(uncompressedPubkey, { coin: 'ETH' })
|
||||||
} else {
|
} else {
|
||||||
kp.address = this.pubkey2address(kp.pubkey, option)
|
kp.address = this.pubkey2address(kp.pubkey, { coin })
|
||||||
}
|
}
|
||||||
return kp
|
return kp
|
||||||
}
|
}
|
||||||
@ -520,17 +523,15 @@ class TICrypto {
|
|||||||
* @return {String} address
|
* @return {String} address
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static secword2address(secword, option) {
|
static secword2address(secword, { coin, pass, path, tool, hasher }) {
|
||||||
option = option || {}
|
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
if (option.coin) option.coin = option.coin.toUpperCase()
|
let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher })
|
||||||
option.coin = my.COIN_LIST.indexOf(option.coin) >= 0 ? option.coin : my.COIN
|
|
||||||
let kp = this.secword2keypair(secword, option)
|
|
||||||
if (kp) {
|
if (kp) {
|
||||||
let address
|
let address
|
||||||
if (option.coin === 'ETH') {
|
if (coin === 'ETH') {
|
||||||
address = this.pubkey2address(this.decompressPubkey(kp.pubkey), { coin: 'ETH' })
|
address = this.pubkey2address(this.decompressPubkey(kp.pubkey), { coin: 'ETH' })
|
||||||
} else {
|
} else {
|
||||||
address = this.pubkey2address(kp.pubkey, option)
|
address = this.pubkey2address(kp.pubkey, { coin })
|
||||||
}
|
}
|
||||||
return address
|
return address
|
||||||
}
|
}
|
||||||
@ -546,18 +547,16 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static seckey2pubkey(seckey, option = {}) {
|
static seckey2pubkey(seckey, { curve, compress } = {}) {
|
||||||
if (option.coin) option.coin = option.coin.toUpperCase()
|
|
||||||
option.coin = my.COIN_LIST.indexOf(option.coin) >= 0 ? option.coin : my.COIN
|
|
||||||
if (this.isSeckey(seckey) && seckey.length === 64) {
|
if (this.isSeckey(seckey) && seckey.length === 64) {
|
||||||
// 只能用于32字节的私钥(BTC, ETH)。也就是不能用于 TIC 的私钥。
|
// 只能用于32字节的私钥(BTC, ETH)。也就是不能用于 TIC 的私钥。
|
||||||
let curve = my.CURVE_LIST.indexOf(option.curve) >= 0 ? option.curve : my.CURVE // 默认为 secp256k1
|
curve = my.CURVE_LIST.indexOf(curve) >= 0 ? curve : my.CURVE // 默认为 secp256k1
|
||||||
// return new crypto.createECDH(curve).setPrivateKey(seckey,'hex').getPublicKey('hex', option.compress===false?'uncompressed':'compressed') // ecdh.getPublicKey(不加参数) 默认为 'compressed'。用 HBuilderX 2.6.4 打包成ios或安卓 app 后 setPrivateKey() 报错:TypeError: null is not an object (evaluating 'this.rand.getBytes')
|
// return new crypto.createECDH(curve).setPrivateKey(seckey,'hex').getPublicKey('hex', compress===false?'uncompressed':'compressed') // ecdh.getPublicKey(不加参数) 默认为 'compressed'。用 HBuilderX 2.6.4 打包成ios或安卓 app 后 setPrivateKey() 报错:TypeError: null is not an object (evaluating 'this.rand.getBytes')
|
||||||
// 从 nodejs 10.0 开始,还有 crypto.ECDH.convertKey 方法,更直接。但可惜,浏览器里不存在 crypto.ECDH。
|
// 从 nodejs 10.0 开始,还有 crypto.ECDH.convertKey 方法,更直接。但可惜,浏览器里不存在 crypto.ECDH。
|
||||||
return this.buf2hex(secp256k1.publicKeyCreate(Buffer.from(seckey, 'hex'), option.compress !== false)) // 可用于浏览器。secp256k1缺省或true时输出压缩公钥,false时输出非压缩公钥。
|
return this.buf2hex(secp256k1.publicKeyCreate(Buffer.from(seckey, 'hex'), compress !== false)) // 可用于浏览器。缺省输出压缩公钥,compress=false时输出非压缩公钥。
|
||||||
// 或者 bitcorelib.PublicKey.fromPrivateKey(new bitcorelib.PrivateKey(seckey)).toString('hex') // 可用于浏览器
|
// 或者 bitcorelib.PublicKey.fromPrivateKey(new bitcorelib.PrivateKey(seckey)).toString('hex') // 可用于浏览器
|
||||||
// 或者 const ecc = require('eccrypto')
|
// 或者 const ecc = require('eccrypto')
|
||||||
// if (option.compress===false){
|
// if (compress===false){
|
||||||
// return ecc.getPublic(this.hex2buf(seckey)).toString('hex')
|
// return ecc.getPublic(this.hex2buf(seckey)).toString('hex')
|
||||||
// }else{
|
// }else{
|
||||||
// return ecc.getPublicCompressed(this.hex2buf(seckey)).toString('hex')
|
// return ecc.getPublicCompressed(this.hex2buf(seckey)).toString('hex')
|
||||||
@ -580,19 +579,17 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static seckey2address(seckey, option) {
|
static seckey2address(seckey, { coin } = {}) {
|
||||||
option = option || {}
|
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
if (option.coin) option.coin = option.coin.toUpperCase()
|
|
||||||
option.coin = my.COIN_LIST.indexOf(option.coin) >= 0 ? option.coin : my.COIN
|
|
||||||
if (this.isSeckey(seckey)) {
|
if (this.isSeckey(seckey)) {
|
||||||
/** @type {*} */
|
/** @type {*} */
|
||||||
let pubkey
|
let pubkey
|
||||||
if (option.coin === 'ETH') {
|
if (coin === 'ETH') {
|
||||||
pubkey = this.seckey2pubkey(seckey, { compress: false })
|
pubkey = this.seckey2pubkey(seckey, { compress: false })
|
||||||
return this.pubkey2address(pubkey, option)
|
return this.pubkey2address(pubkey, { coin })
|
||||||
} else {
|
} else {
|
||||||
pubkey = this.seckey2pubkey(seckey, { compress: true })
|
pubkey = this.seckey2pubkey(seckey, { compress: true })
|
||||||
return this.pubkey2address(pubkey, option)
|
return this.pubkey2address(pubkey, { coin })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -609,8 +606,7 @@ class TICrypto {
|
|||||||
*/
|
*/
|
||||||
static pubkey2position(pubkey, { coin } = {}) {
|
static pubkey2position(pubkey, { coin } = {}) {
|
||||||
// tic, btc, eth 的 position 都是 20节=40字符的。
|
// tic, btc, eth 的 position 都是 20节=40字符的。
|
||||||
if (coin) coin = coin.toUpperCase()
|
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
coin = my.COIN_LIST.indexOf(coin) >= 0 ? coin : my.COIN
|
|
||||||
if (this.isPubkey(pubkey)) {
|
if (this.isPubkey(pubkey)) {
|
||||||
if (coin === 'ETH') {
|
if (coin === 'ETH') {
|
||||||
// 注意,必须要用非压缩的64字节的公钥的buffer,并去掉开头的 04。
|
// 注意,必须要用非压缩的64字节的公钥的buffer,并去掉开头的 04。
|
||||||
@ -774,11 +770,10 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static pubkey2address(pubkey, option = {}) {
|
static pubkey2address(pubkey, { coin } = {}) {
|
||||||
// pubkey 应当是string类型
|
// pubkey 应当是string类型
|
||||||
if (option.coin) option.coin = option.coin.toUpperCase()
|
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
option.coin = my.COIN_LIST.indexOf(option.coin) >= 0 ? option.coin : my.COIN
|
return this.position2address(this.pubkey2position(pubkey, { coin }), { coin })
|
||||||
return this.position2address(this.pubkey2position(pubkey, option), option)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -847,11 +842,10 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomSeckey(option = {}) {
|
static randomSeckey({ coin, tool } = {}) {
|
||||||
// 跳过 secword 直接产生随机密钥
|
// 跳过 secword 直接产生随机密钥
|
||||||
if (option.coin) option.coin = option.coin.toUpperCase()
|
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin : my.COIN
|
||||||
option.coin = my.COIN_LIST.indexOf(option.coin) >= 0 ? option.coin : my.COIN
|
if (tool === 'nacl') {
|
||||||
if (option.tool === 'nacl') {
|
|
||||||
return crypto.randomBytes(64).toString('hex') // Buffer.from(nacl.sign.keyPair().secretKey).toString('hex') // 64字节
|
return crypto.randomBytes(64).toString('hex') // Buffer.from(nacl.sign.keyPair().secretKey).toString('hex') // 64字节
|
||||||
} else {
|
} else {
|
||||||
return crypto.randomBytes(32).toString('hex') // Buffer.from(nacl.box.keyPair().secretKey).toString('hex') // 32字节
|
return crypto.randomBytes(32).toString('hex') // Buffer.from(nacl.box.keyPair().secretKey).toString('hex') // 32字节
|
||||||
@ -866,12 +860,10 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomKeypair(option = {}) {
|
static randomKeypair({ tool, purpose } = {}) {
|
||||||
if (option.coin) option.coin = option.coin.toUpperCase()
|
|
||||||
option.coin = my.COIN_LIST.indexOf(option.coin) >= 0 ? option.coin : my.COIN
|
|
||||||
let kp
|
let kp
|
||||||
if (option.tool === 'nacl') {
|
if (tool === 'nacl') {
|
||||||
if (option.purpose === 'encrypt') {
|
if (purpose === 'encrypt') {
|
||||||
kp = nacl.box.keyPair()
|
kp = nacl.box.keyPair()
|
||||||
} else {
|
} else {
|
||||||
kp = nacl.sign.keyPair()
|
kp = nacl.sign.keyPair()
|
||||||
@ -898,9 +890,9 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomAccount(option = {}) {
|
static randomAccount({ lang, coin, pass, path, tool, hasher } = {}) {
|
||||||
let secword = this.randomSecword(option.lang)
|
let secword = this.randomSecword(lang)
|
||||||
return this.secword2account(secword, option)
|
return this.secword2account(secword, { coin, pass, path, tool, hasher })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -984,15 +976,14 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static getMerkleHash(hashList, option = {}) {
|
static getMerkleHash(hashList, { output, hasher } = {}) {
|
||||||
// merkle算法略有难度,暂时用最简单的hash代替
|
// merkle算法略有难度,暂时用最简单的hash代替
|
||||||
if (Array.isArray(hashList)) {
|
if (Array.isArray(hashList)) {
|
||||||
let output = option.output === 'buf' ? undefined : option.output || my.OUTPUT
|
myhasher = crypto.createHash(my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER)
|
||||||
let hasher = crypto.createHash(my.HASHER_LIST.indexOf(option.hasher) >= 0 ? option.hasher : my.HASHER)
|
|
||||||
for (var hash of hashList) {
|
for (var hash of hashList) {
|
||||||
hasher.update(hash)
|
myhasher.update(hash)
|
||||||
}
|
}
|
||||||
return hasher.digest(output)
|
return myhasher.digest(output === 'buf' ? undefined : output || my.OUTPUT)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -1006,7 +997,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static getMerkleRoot(todoHashList, option) {
|
static getMerkleRoot(todoHashList) {
|
||||||
//深拷贝传入数组,防止引用对象被改变
|
//深拷贝传入数组,防止引用对象被改变
|
||||||
let hashList = [...todoHashList]
|
let hashList = [...todoHashList]
|
||||||
if (!Array.isArray(hashList)) return null
|
if (!Array.isArray(hashList)) return null
|
||||||
|
Loading…
Reference in New Issue
Block a user