This commit is contained in:
陆柯 2022-06-02 13:06:42 +08:00
parent 32b36dff0a
commit c2adfd5a14

158
index.js
View File

@ -30,7 +30,7 @@ my.OUTPUT_LIST = ['hex', 'latin1', 'base64'] // or 'buf' to Buffer explicitly
my.INPUT = 'utf8' // 默认的加密方法的明文格式。utf8 能够兼容 latin1, ascii 的情形 my.INPUT = 'utf8' // 默认的加密方法的明文格式。utf8 能够兼容 latin1, ascii 的情形
my.INPUT_LIST = ['utf8', 'ascii', 'latin1'] // ignored for Buffer/TypedArray/DataView my.INPUT_LIST = ['utf8', 'ascii', 'latin1'] // ignored for Buffer/TypedArray/DataView
my.COIN = 'TIC' // 默认的币种 my.COIN = 'TIC' // 默认的币种
my.COIN_LIST = ['TIC', 'EXT', 'BTC', 'ETH'] my.COIN_LIST = ['TIC', 'BTC', 'ETH']
my.REGEXP_ALPHABET = { my.REGEXP_ALPHABET = {
hex: /^[0-9a-fA-F]+$/, hex: /^[0-9a-fA-F]+$/,
b32: /^[A-Za-z2-7=]+$/, b32: /^[A-Za-z2-7=]+$/,
@ -74,7 +74,7 @@ class TICrypto {
* @memberof TICrypto * @memberof TICrypto
*/ */
static isHash (hash, { hasher = my.HASHER } = {}) { static isHash (hash, { hasher = my.HASHER } = {}) {
if (my.HASHER_LIST.indexOf(hasher) >= 0) { if (my.HASHER_LIST.includes(hasher)) {
switch (hasher) { switch (hasher) {
case 'sha256': case 'sha256':
return /^[a-fA-F0-9]{64}$/.test(hash) return /^[a-fA-F0-9]{64}$/.test(hash)
@ -173,8 +173,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(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 inputEncoding = input // my.INPUT_LIST.includes(input)?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) // output: 留空=》默认输出hex格式或者手动指定 'buf', hex', 'latin1' or 'base64' let outputEncoding = output === 'buf' ? undefined : output // (my.OUTPUT_LIST.includes(output)?output:my.OUTPUT) // output: 留空=》默认输出hex格式或者手动指定 'buf', hex', 'latin1' or 'base64'
return crypto return crypto
.createHash(hasher) .createHash(hasher)
.update(data, inputEncoding) .update(data, inputEncoding)
@ -203,10 +203,10 @@ class TICrypto {
} else if (keytype === 'pwd') { } else if (keytype === 'pwd') {
// 对称加密 // 对称加密
if (typeof key === 'string') { if (typeof key === 'string') {
let inputEncoding = my.INPUT_LIST.indexOf(input) >= 0 ? input : my.INPUT // 'utf8' by default, 'ascii', 'latin1' for string or ignored for Buffer/TypedArray/DataView let inputEncoding = my.INPUT_LIST.includes(input) ? input : my.INPUT // 'utf8' by default, 'ascii', 'latin1' for string or ignored for Buffer/TypedArray/DataView
let outputEncoding = output === 'buf' ? undefined : my.OUTPUT_LIST.indexOf(output) >= 0 ? output : my.OUTPUT // 'latin1', 'base64', 'hex' by default or 'buf' to Buffer explicitly let outputEncoding = output === 'buf' ? undefined : my.OUTPUT_LIST.includes(output) ? output : my.OUTPUT // 'latin1', 'base64', 'hex' by default or 'buf' to Buffer explicitly
const iv = crypto.randomBytes(16) const iv = crypto.randomBytes(16)
let encryptor = crypto.createCipheriv(my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER, this.hex_to_buf(this.hash(key)), iv) // cipher 和 key 的长度必须相同,例如 cipher 是 ***-192那么 key 就必须是 192/8=24 字节 = 48 hex 的。 let encryptor = crypto.createCipheriv(my.CIPHER_LIST.includes(cipher) ? cipher : my.CIPHER, this.hex_to_buf(this.hash(key)), iv) // cipher 和 key 的长度必须相同,例如 cipher 是 ***-192那么 key 就必须是 192/8=24 字节 = 48 hex 的。
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)
let ciphertext = encryptor.update(data, inputEncoding, outputEncoding) let ciphertext = encryptor.update(data, inputEncoding, outputEncoding)
ciphertext += encryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string ciphertext += encryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string
@ -248,10 +248,10 @@ class TICrypto {
} else if (keytype === 'pwd') { } else if (keytype === 'pwd') {
// 对称解密 // 对称解密
if ((typeof data.ciphertext === 'string' || data.ciphertext instanceof Buffer) && typeof key === 'string') { if ((typeof data.ciphertext === 'string' || data.ciphertext instanceof Buffer) && typeof key === 'string') {
let inputEncoding = my.OUTPUT_LIST.indexOf(input) >= 0 ? input : my.OUTPUT // input (=output of encrypt) could be 'latin1', 'base64', 'hex' by default for string or ignored for Buffer let inputEncoding = my.OUTPUT_LIST.includes(input) ? input : my.OUTPUT // input (=output of encrypt) could be 'latin1', 'base64', 'hex' by default for string or ignored for Buffer
let outputEncoding = output === 'buf' ? undefined : my.INPUT_LIST.indexOf(output) >= 0 ? output : my.INPUT // output (=input of encrypt) could be 'latin1', 'ascii', 'utf8' by default or 'buf' to Buffer explicitly let outputEncoding = output === 'buf' ? undefined : my.INPUT_LIST.includes(output) ? output : my.INPUT // output (=input of encrypt) could be 'latin1', 'ascii', 'utf8' by default or 'buf' to Buffer explicitly
let decryptor = crypto.createDecipheriv( let decryptor = crypto.createDecipheriv(
my.CIPHER_LIST.indexOf(cipher) >= 0 ? cipher : my.CIPHER, my.CIPHER_LIST.includes(cipher) ? cipher : my.CIPHER,
this.hex_to_buf(this.hash(key)), this.hex_to_buf(this.hash(key)),
Buffer.from(data.iv, 'hex') Buffer.from(data.iv, 'hex')
) )
@ -296,11 +296,11 @@ class TICrypto {
} else if (seckey.length === 64) { } else if (seckey.length === 64) {
// 纯 crypto // 纯 crypto
let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(seckey), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(seckey), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
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, 其他都会报错。 let signer = crypto.createSign(my.HASHER_LIST.includes(hasher) ? 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 方法,但在浏览器中无效: // 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') // let signature = crypto.sign(my.HASHER_LIST.includes(hasher) ? 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却是固定的。
} }
} }
@ -339,11 +339,11 @@ class TICrypto {
} else if (signature.length >= 140) { } else if (signature.length >= 140) {
// 纯 crypto // 发现大小写不影响 crypto 验签!都能通过 // 纯 crypto // 发现大小写不影响 crypto 验签!都能通过
let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(pubkey), { namedCurve: 'P-256K' }).export('pem') // 公钥导出的der格式为88字节。经测试同一对压缩和非压缩公钥得出的结果一模一样。 let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(pubkey), { namedCurve: 'P-256K' }).export('pem') // 公钥导出的der格式为88字节。经测试同一对压缩和非压缩公钥得出的结果一模一样。
let verifier = crypto.createVerify(my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER) let verifier = crypto.createVerify(my.HASHER_LIST.includes(hasher) ? 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位hexcrypto 的 verify结果也是true! 估计因为一位hex不被转成字节。但减少1位会导致false let verified = verifier.verify(pubkeyPEM, signature, 'hex') // 如果给signature添加1位hexcrypto 的 verify结果也是true! 估计因为一位hex不被转成字节。但减少1位会导致false
// since nodejs 12, 有了 crypto.verify 方法,但在浏览器中无效: // 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')) // let verified = crypto.verify(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER, Buffer.from(this.hash(data)), pubkeyPEM, Buffer.from(signature, 'hex'))
return verified return verified
} }
} }
@ -362,7 +362,7 @@ class TICrypto {
static pass2keypair (pass, { hasher } = {}) { static pass2keypair (pass, { hasher } = {}) {
// 如果使用其他机制例如密码、随机数不使用secword也可生成keypair // 如果使用其他机制例如密码、随机数不使用secword也可生成keypair
if (this.isHashable(pass)) { if (this.isHashable(pass)) {
hasher = my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER
var hashBuf = crypto var hashBuf = crypto
.createHash(hasher) .createHash(hasher)
.update(pass) .update(pass)
@ -424,11 +424,11 @@ 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/...
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN coin = coin?.toUpperCase() || my.COIN
if (tool === 'nacl') { if (tool === 'nacl') {
// 采用自己的算法bip39算法从secword到种子hash后用 nacl.sign.keyPair.fromSeed()方法。 // 采用自己的算法bip39算法从secword到种子hash后用 nacl.sign.keyPair.fromSeed()方法。
hasher = my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER
let hashBuf = crypto let hashBuf = crypto
.createHash(hasher) .createHash(hasher)
.update(this.secword2seed(secword, pass)) .update(this.secword2seed(secword, pass))
@ -447,25 +447,9 @@ class TICrypto {
let key = hdmaster let key = hdmaster
if (path === 'master') { if (path === 'master') {
key = hdmaster key = hdmaster
} else if (!path) {
switch (coin) {
case 'BTC':
key = hdmaster.derive("m/44'/0'/0'/0/0")
break
case 'ETH':
key = hdmaster.derive("m/44'/60'/0'/0/0")
break
case 'EXT':
key = hdmaster.derive("m/44'/60398'/0'/0/0")
break
case 'TIC':
default:
key = hdmaster.derive("m/44'/60000'/0'/0/0")
break
}
} else { } else {
// 指定了路径 path,例如 "m/44'/0'/0'/0/6" 或 "m/0/2147483647'/1" // 指定了路径 path 例如 "m/0/2147483647'/1" 则用 path否则调用 seed2path() 来获取默认的根路径 例如 "m/44'/0'/0'/0/0" 或 "m/44'/60'/0'/0/0"
key = hdmaster.derive(path) key = hdmaster.derive(path || this.seed2path({ coin }))
} }
return { return {
coin: coin, coin: coin,
@ -482,34 +466,54 @@ class TICrypto {
* *
* @static * @static
* @param {*} seed * @param {*} seed
* @param {string} option [{ coin = 'TIC' }={ coin: 'TIC' }] * @param {string} option [{ coin = my.COIN }={ coin: my.COIN }]
* @return {String} path * @return {String} path
* @memberof TICrypto * @memberof TICrypto
*/ */
static seed2path (seed, { coin = 'TIC' } = { coin: 'TIC' }) { static seed2path ({ seed, coin = my.COIN } = { coin: my.COIN }) {
// 路径规范 BIP44: m/Purpose'/Coin'/Account'/Change/Index, // 路径规范 BIP44: m/Purpose'/Coin'/Account'/Change/Index,
// 但实际上 Purpose, Coin 都可任意定;' 可有可无; // 但实际上 Purpose, Coin 都可任意定;' 可有可无;
// Account/Change/Index 最大到 parseInt(0x7FFFFFFF, 16) // Account/Change/Index 最大到 parseInt(0x7FFFFFFF, 16)
// 后面还可继续延伸 /xxx/xxx/xxx/...... // 后面还可继续延伸 /xxx/xxx/xxx/......
let hash = this.hash(seed, { hasher: 'md5' }) let path
let part0 = parseInt(hash.slice(0, 6), 16) if (seed) {
let part1 = parseInt(hash.slice(6, 12), 16) let hash = this.hash(seed, { hasher: 'md5' })
let part2 = parseInt(hash.slice(12, 18), 16) let part0 = parseInt(hash.slice(0, 6), 16)
let part3 = parseInt(hash.slice(18, 24), 16) let part1 = parseInt(hash.slice(6, 12), 16)
let part4 = parseInt(hash.slice(24, 30), 16) let part2 = parseInt(hash.slice(12, 18), 16)
let part5 = parseInt(hash.slice(30, 32), 16) let part3 = parseInt(hash.slice(18, 24), 16)
let path = `${part0}'/${part1}/${part2}/${part3}/${part4}/${part5}` let part4 = parseInt(hash.slice(24, 30), 16)
switch (coin.toUpperCase()) { let part5 = parseInt(hash.slice(30, 32), 16)
case 'BTC': path = `${part0}'/${part1}/${part2}/${part3}/${part4}/${part5}`
return `m/44'/0'/${path}` } else {
case 'ETH': path = "0'/0/0"
return `m/44'/60'/${path}`
case 'EXT':
return `m/44'/60398'/${path}`
case 'TIC':
default:
return `m/44'/60000'/${path}`
} }
coin = coin.toUpperCase() || my.COIN
if (coin === 'BTC') {
return `m/44'/0'/${path}`
} else if (coin === 'ETH') {
return `m/44'/60'/${path}`
} else if (coin === 'TIC' || !coin) {
return `m/44'/60000'/${path}`
} else if (/[A-Z]{3}/.test(coin)) {
return `m/44'/60${this.alpha_to_digit(coin)}'/${path}`
} else {
return ''
}
}
static alpha_to_digit (name = '') {
let digits = name
.toLowerCase()
.replace(/[abc]/g, 2)
.replace(/[def]/g, 3)
.replace(/[ghi]/g, 4)
.replace(/[jkl]/g, 5)
.replace(/[mno]/g, 6)
.replace(/[pqrs]/g, 7)
.replace(/[tuv]/g, 8)
.replace(/[wxyz]/g, 9)
return parseInt(digits)
} }
/** /**
@ -523,7 +527,7 @@ class TICrypto {
*/ */
static secword2account (secword, { coin, pass, path, tool, hasher } = {}) { static secword2account (secword, { coin, pass, path, tool, hasher } = {}) {
// account 比 keypair 多了 address 字段。 // account 比 keypair 多了 address 字段。
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN coin = coin?.toUpperCase() || my.COIN
let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher }) let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher })
if (kp) { if (kp) {
if (coin === 'ETH') { if (coin === 'ETH') {
@ -547,7 +551,7 @@ class TICrypto {
* @memberof TICrypto * @memberof TICrypto
*/ */
static secword2address (secword, { coin, world, pass, path, tool, hasher } = {}) { static secword2address (secword, { coin, world, pass, path, tool, hasher } = {}) {
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN coin = coin?.toUpperCase() || my.COIN
let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher }) let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher })
if (kp) { if (kp) {
let address let address
@ -573,7 +577,7 @@ class TICrypto {
static seckey2pubkey (seckey, { curve, compress } = {}) { static seckey2pubkey (seckey, { curve, compress } = {}) {
if (this.isSeckey(seckey) && seckey.length === 64) { if (this.isSeckey(seckey) && seckey.length === 64) {
// 只能用于32字节的私钥BTC, ETH)。也就是不能用于 TIC 的私钥。 // 只能用于32字节的私钥BTC, ETH)。也就是不能用于 TIC 的私钥。
curve = my.CURVE_LIST.indexOf(curve) >= 0 ? curve : my.CURVE // 默认为 secp256k1 curve = my.CURVE_LIST.includes(curve) ? curve : my.CURVE // 默认为 secp256k1
// 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') // 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.buf_to_hex(secp256k1.publicKeyCreate(Buffer.from(seckey, 'hex'), compress !== false)) // 可用于浏览器。缺省输出压缩公钥compress=false时输出非压缩公钥。 return this.buf_to_hex(secp256k1.publicKeyCreate(Buffer.from(seckey, 'hex'), compress !== false)) // 可用于浏览器。缺省输出压缩公钥compress=false时输出非压缩公钥。
@ -603,7 +607,7 @@ class TICrypto {
* @memberof TICrypto * @memberof TICrypto
*/ */
static seckey2address (seckey, { coin, world } = {}) { static seckey2address (seckey, { coin, world } = {}) {
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN coin = coin?.toUpperCase() || my.COIN
if (this.isSeckey(seckey)) { if (this.isSeckey(seckey)) {
/** @type {*} */ /** @type {*} */
let pubkey let pubkey
@ -630,7 +634,7 @@ class TICrypto {
*/ */
static pubkey2position (pubkey, { coin } = {}) { static pubkey2position (pubkey, { coin } = {}) {
// tic, btc, eth 的 position 都是 20节=40字符的。 // tic, btc, eth 的 position 都是 20节=40字符的。
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN coin = coin?.toUpperCase() || my.COIN
if (this.isPubkey(pubkey)) { if (this.isPubkey(pubkey)) {
if (coin === 'ETH') { if (coin === 'ETH') {
// 注意必须要用非压缩的64字节的公钥的buffer并去掉开头的 04。 // 注意必须要用非压缩的64字节的公钥的buffer并去掉开头的 04。
@ -667,8 +671,7 @@ class TICrypto {
*/ */
static position2address (position, { coin, world } = {}) { static position2address (position, { coin, world } = {}) {
if (!/^[\da-fA-F]{40}$/.test(position)) return null // 不论 tic, btc, eth其 position 都是 40字符的。 if (!/^[\da-fA-F]{40}$/.test(position)) return null // 不论 tic, btc, eth其 position 都是 40字符的。
if (coin) coin = coin.toUpperCase() coin = coin?.toUpperCase() || my.COIN
coin = my.COIN_LIST.indexOf(coin) >= 0 ? coin : my.COIN
let address let address
if (coin === 'ETH') { if (coin === 'ETH') {
// 对以太坊,按照 EIP55把纯位置转换为大小写敏感能自我验证的hex地址。仍然为20节=40符。 // 对以太坊,按照 EIP55把纯位置转换为大小写敏感能自我验证的hex地址。仍然为20节=40符。
@ -809,7 +812,7 @@ class TICrypto {
*/ */
static pubkey2address (pubkey, { coin, world } = {}) { static pubkey2address (pubkey, { coin, world } = {}) {
// pubkey 应当是string类型 // pubkey 应当是string类型
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN coin = coin?.toUpperCase() || my.COIN
return this.position2address(this.pubkey2position(pubkey, { coin }), { coin, world }) return this.position2address(this.pubkey2position(pubkey, { coin }), { coin, world })
} }
@ -839,9 +842,9 @@ class TICrypto {
static randomSecword (lang = 'english') { static randomSecword (lang = 'english') {
// accepts case-insensitive lang, such as 'chinese, cn, tw, en' // accepts case-insensitive lang, such as 'chinese, cn, tw, en'
//// for BitcoreMnemonic //// for BitcoreMnemonic
// lang=lang.toUpperCase() // lang=lang?.toUpperCase()
// let language = { ZHCN: 'CHINESE', ENUS: 'ENGLISH', FRFR: 'FRENCH', ITIT: 'ITALIAN', JAJP: 'JAPANESE', KOKR: 'KOREAN', ESES: 'SPANISH' }[lang] // let language = { ZHCN: 'CHINESE', ENUS: 'ENGLISH', FRFR: 'FRENCH', ITIT: 'ITALIAN', JAJP: 'JAPANESE', KOKR: 'KOREAN', ESES: 'SPANISH' }[lang]
// || (BitcoreMnemonic.Words.hasOwnProperty(lang.toUpperCase()) ? lang.toUpperCase() : 'ENGLISH') // || (BitcoreMnemonic.Words.hasOwnProperty(lang?.toUpperCase()) ? lang?.toUpperCase() : 'ENGLISH')
// return new BitcoreMnemonic(BitcoreMnemonic.Words[language]).phrase // return new BitcoreMnemonic(BitcoreMnemonic.Words[language]).phrase
// for bip39 // for bip39
@ -882,7 +885,6 @@ class TICrypto {
*/ */
static randomSeckey ({ coin, tool } = {}) { static randomSeckey ({ coin, tool } = {}) {
// 跳过 secword 直接产生随机密钥 // 跳过 secword 直接产生随机密钥
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin : my.COIN
if (tool === 'nacl') { if (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 {
@ -1017,7 +1019,7 @@ class TICrypto {
static getMerkleHash (hashList, { output, hasher } = {}) { static getMerkleHash (hashList, { output, hasher } = {}) {
// merkle算法略有难度暂时用最简单的hash代替 // merkle算法略有难度暂时用最简单的hash代替
if (Array.isArray(hashList)) { if (Array.isArray(hashList)) {
myhasher = crypto.createHash(my.HASHER_LIST.indexOf(hasher) >= 0 ? hasher : my.HASHER) myhasher = crypto.createHash(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER)
for (var hash of hashList) { for (var hash of hashList) {
myhasher.update(hash) myhasher.update(hash)
} }
@ -1477,29 +1479,33 @@ class TICrypto {
const multicodec = { const multicodec = {
dagpb: '70', dagpb: '70',
p2pkey: '72', p2pkey: '72',
raw: '55' raw: '55',
} }
const multialgo = { const multialgo = {
identify: '00', identify: '00',
sha256: '12' sha256: '12',
} }
if (cidVersion === 0) { if (cidVersion === 0) {
return this.hex_to_b58(`${multialgo[cidAlgo]}${Number(cosh.length/2).toString(16)}${cosh}`) return this.hex_to_b58(`${multialgo[cidAlgo]}${Number(cosh.length / 2).toString(16)}${cosh}`)
} }
if (cidVersion === 1) { if (cidVersion === 1) {
let fullHex = `01${multicodec[cidCodec]}${multialgo[cidAlgo]}${Number(cosh.length/2).toString(16)}${cosh}` let fullHex = `01${multicodec[cidCodec]}${multialgo[cidAlgo]}${Number(cosh.length / 2).toString(16)}${cosh}`
if (cidBase==='b32') { if (cidBase === 'b32') {
return multibase[cidBase] + this.hex_to_b32(fullHex).toLowerCase().replace(/=/g,'') return (
}else if (cidBase==='b58') { multibase[cidBase] +
this.hex_to_b32(fullHex)
.toLowerCase()
.replace(/=/g, '')
)
} else if (cidBase === 'b58') {
return multibase[cidBase] + this.hex_to_b58(fullHex) return multibase[cidBase] + this.hex_to_b58(fullHex)
} }
} }
} }
static string_to_raw_cid (str) { static string_to_raw_cid (str) {
return this.cosh_to_cid({ cosh: this.hash(str), cidVersion:1, cidCodec:'raw' }) return this.cosh_to_cid({ cosh: this.hash(str), cidVersion: 1, cidCodec: 'raw' })
} }
} }
// 必须单独写 module.exports不要和类定义写在一起否则会导致 jsdoc 解析不到类内文档。 // 必须单独写 module.exports不要和类定义写在一起否则会导致 jsdoc 解析不到类内文档。