添加 cid 转换函数
This commit is contained in:
parent
447a3eb442
commit
74694866bc
243
index.js
243
index.js
@ -31,6 +31,17 @@ my.INPUT = 'utf8' // 默认的加密方法的明文格式。utf8 能够兼容 la
|
|||||||
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', 'EXT', 'BTC', 'ETH']
|
||||||
|
my.REGEXP_ALPHABET = {
|
||||||
|
hex: /^[0-9a-fA-F]+$/,
|
||||||
|
b32: /^[A-Za-z2-7=]+$/,
|
||||||
|
b32h: /^[0-9A-Va-v=]+$/,
|
||||||
|
b36: /^[0-9A-Z-a-z]+$/,
|
||||||
|
b58: /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/,
|
||||||
|
b62: /^[A-Za-z0-9]+$/,
|
||||||
|
b64: /^[A-Za-z0-9\+\/=]+$/,
|
||||||
|
b64u: /^[A-Za-z0-9\-_]+$/,
|
||||||
|
b64t: /^[A-Za-z0-9\._]+$/,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -46,7 +57,7 @@ class TICrypto {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static isHashable(data, { strict = false } = {}) {
|
static isHashable (data, { strict = false } = {}) {
|
||||||
if (strict) {
|
if (strict) {
|
||||||
return typeof data !== 'boolean' && data !== Infinity && data ? true : false // 允许大多数数据,除了null、''、0、布尔值、无限数。注意 data 要放在最后,否则会被 return 直接返回,而不是返回 Boolean
|
return typeof data !== 'boolean' && data !== Infinity && data ? true : false // 允许大多数数据,除了null、''、0、布尔值、无限数。注意 data 要放在最后,否则会被 return 直接返回,而不是返回 Boolean
|
||||||
}
|
}
|
||||||
@ -62,7 +73,7 @@ class TICrypto {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @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.indexOf(hasher) >= 0) {
|
||||||
switch (hasher) {
|
switch (hasher) {
|
||||||
case 'sha256':
|
case 'sha256':
|
||||||
@ -88,7 +99,7 @@ class TICrypto {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static isSecword(secword, { mode = 'strict' } = {}) {
|
static isSecword (secword, { mode = 'strict' } = {}) {
|
||||||
// 注意 not all 12 words combinations are valid for both bitcore and bip39, because there are checksum in mnemonic. 另外,实际上bitcore和bip39对12, 15, 18, ... 长度的合法助记词都返回 true。
|
// 注意 not all 12 words combinations are valid for both bitcore and bip39, because there are checksum in mnemonic. 另外,实际上bitcore和bip39对12, 15, 18, ... 长度的合法助记词都返回 true。
|
||||||
//// for bitcore-mnemonic. 注意,bitcore-mnemonic 对少于12词的会抛出异常,很蠢。
|
//// for bitcore-mnemonic. 注意,bitcore-mnemonic 对少于12词的会抛出异常,很蠢。
|
||||||
// if (typeof secword==='string' && 12===secword.split(/ +/).length)
|
// if (typeof secword==='string' && 12===secword.split(/ +/).length)
|
||||||
@ -115,7 +126,7 @@ class TICrypto {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static isSeckey(seckey) {
|
static isSeckey (seckey) {
|
||||||
// 比特币、以太坊的私钥:64 hex
|
// 比特币、以太坊的私钥:64 hex
|
||||||
// nacl.sign 的私钥 128 hex, nacl.box 的私钥 64 hex
|
// nacl.sign 的私钥 128 hex, nacl.box 的私钥 64 hex
|
||||||
return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(seckey)
|
return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(seckey)
|
||||||
@ -129,7 +140,7 @@ class TICrypto {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static isPubkey(pubkey) {
|
static isPubkey (pubkey) {
|
||||||
// 比特币的公钥:压缩型 '02|03' + 64 hex 或 无压缩型 '04' + 128 hex
|
// 比特币的公钥:压缩型 '02|03' + 64 hex 或 无压缩型 '04' + 128 hex
|
||||||
// 以太坊的公钥:'02|03' + 64 hex
|
// 以太坊的公钥:'02|03' + 64 hex
|
||||||
// nacl.sign 的公钥:64 hex
|
// nacl.sign 的公钥:64 hex
|
||||||
@ -144,7 +155,7 @@ class TICrypto {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static isSignature(signature) {
|
static isSignature (signature) {
|
||||||
return /^[a-fA-F0-9]{128,144}$/.test(signature) && signature.length % 2 === 0 // 128 for nacl, 140/142/144 for crypto and eccrypto in der format.
|
return /^[a-fA-F0-9]{128,144}$/.test(signature) && signature.length % 2 === 0 // 128 for nacl, 140/142/144 for crypto and eccrypto in der format.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,14 +168,17 @@ class TICrypto {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static hash(data, { hasher = my.HASHER, salt, input = my.INPUT, output = my.OUTPUT } = {}) {
|
static hash (data, { hasher = my.HASHER, salt, input = my.INPUT, output = my.OUTPUT } = {}) {
|
||||||
// data can be anything, but converts to string or remains be Buffer/TypedArray/DataView
|
// data can be anything, but converts to string or remains be Buffer/TypedArray/DataView
|
||||||
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.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) // 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
|
||||||
}
|
}
|
||||||
@ -178,7 +192,7 @@ class TICrypto {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static async encrypt({ data, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
|
static async encrypt ({ data, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
|
||||||
if (tool === 'eccrypto') {
|
if (tool === 'eccrypto') {
|
||||||
// data 应当是 utf8 的字符串。key 必须是 pubkey
|
// data 应当是 utf8 的字符串。key 必须是 pubkey
|
||||||
// eccrypto 能用 Uint8Array 和 Buffer
|
// eccrypto 能用 Uint8Array 和 Buffer
|
||||||
@ -218,7 +232,7 @@ class TICrypto {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static async decrypt({ data = {}, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
|
static async decrypt ({ data = {}, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
|
||||||
// data 应当是 encrypt 输出的数据类型
|
// data 应当是 encrypt 输出的数据类型
|
||||||
if (tool === 'eccrypto') {
|
if (tool === 'eccrypto') {
|
||||||
try {
|
try {
|
||||||
@ -267,7 +281,7 @@ class TICrypto {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static async sign({ data, seckey, tool = 'crypto', hasher }) {
|
static async sign ({ data, seckey, tool = 'crypto', hasher }) {
|
||||||
// data can be string or buffer or object, results are the same
|
// data can be string or buffer or object, results are the same
|
||||||
if (this.isHashable(data) && this.isSeckey(seckey)) {
|
if (this.isHashable(data) && this.isSeckey(seckey)) {
|
||||||
if (tool === 'nacl' && seckey.length === 128) {
|
if (tool === 'nacl' && seckey.length === 128) {
|
||||||
@ -304,7 +318,7 @@ class TICrypto {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static async verify({ data, signature, pubkey, tool = 'crypto', hasher }) {
|
static async verify ({ data, signature, pubkey, tool = 'crypto', hasher }) {
|
||||||
// data could be anything, but converts to string or remains be Buffer/TypedArray/DataView
|
// data could be anything, but converts to string or remains be Buffer/TypedArray/DataView
|
||||||
if (this.isHashable(data) && this.isSignature(signature) && this.isPubkey(pubkey)) {
|
if (this.isHashable(data) && this.isSignature(signature) && this.isPubkey(pubkey)) {
|
||||||
if ('nacl' === tool && signature.length === 128) {
|
if ('nacl' === tool && signature.length === 128) {
|
||||||
@ -345,11 +359,14 @@ class TICrypto {
|
|||||||
* @return {Object} {pubkey, seckey, address,}
|
* @return {Object} {pubkey, seckey, address,}
|
||||||
* @memberof TICrypto
|
* @memberof 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.indexOf(hasher) >= 0 ? hasher : my.HASHER
|
||||||
var hashBuf = crypto.createHash(hasher).update(pass).digest()
|
var hashBuf = crypto
|
||||||
|
.createHash(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'),
|
||||||
@ -368,7 +385,7 @@ class TICrypto {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static entropy2secword(entropy) {
|
static entropy2secword (entropy) {
|
||||||
// entropy could be hex string or buffer. Byte length could be of 16, 20, 24, 28, ... which outputs mnemonic of length 12, 15, 18, 21, ...
|
// entropy could be hex string or buffer. Byte length could be of 16, 20, 24, 28, ... which outputs mnemonic of length 12, 15, 18, 21, ...
|
||||||
return bip39.entropyToMnemonic(entropy) // results are the same for the same entropy.
|
return bip39.entropyToMnemonic(entropy) // results are the same for the same entropy.
|
||||||
}
|
}
|
||||||
@ -381,7 +398,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static secword2entropy(secword) {
|
static secword2entropy (secword) {
|
||||||
// secword could be of length 12, 15, 18, ... which outputs hex of length 32, 40, ...
|
// secword could be of length 12, 15, 18, ... which outputs hex of length 32, 40, ...
|
||||||
return bip39.mnemonicToEntropy(secword) // results are the same for the same secword.
|
return bip39.mnemonicToEntropy(secword) // results are the same for the same secword.
|
||||||
}
|
}
|
||||||
@ -395,7 +412,7 @@ class TICrypto {
|
|||||||
* @return {Object} {pubkey, seckey,}
|
* @return {Object} {pubkey, seckey,}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static secword2keypair(secword, { coin, pass, path, tool, hasher } = {}) {
|
static secword2keypair (secword, { coin, pass, path, tool, hasher } = {}) {
|
||||||
// coin 币种;
|
// coin 币种;
|
||||||
// passphase 密码,默认为空;
|
// passphase 密码,默认为空;
|
||||||
// path==='master' 生成 HD master key,不定义则默认为相应币种的第一对公私钥。
|
// path==='master' 生成 HD master key,不定义则默认为相应币种的第一对公私钥。
|
||||||
@ -412,7 +429,10 @@ class TICrypto {
|
|||||||
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.indexOf(hasher) >= 0 ? hasher : my.HASHER
|
||||||
let hashBuf = crypto.createHash(hasher).update(this.secword2seed(secword, 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: coin,
|
coin: coin,
|
||||||
@ -466,7 +486,7 @@ class TICrypto {
|
|||||||
* @return {String} path
|
* @return {String} path
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static seed2path(seed, { coin = 'TIC' } = { coin: 'TIC' }) {
|
static seed2path (seed, { coin = 'TIC' } = { coin: 'TIC' }) {
|
||||||
// 路径规范 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)
|
||||||
@ -501,7 +521,7 @@ class TICrypto {
|
|||||||
* @return {Object}
|
* @return {Object}
|
||||||
* @memberof TICrypto
|
* @memberof 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 = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher })
|
let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher })
|
||||||
@ -526,7 +546,7 @@ class TICrypto {
|
|||||||
* @return {String} address
|
* @return {String} address
|
||||||
* @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 = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? 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) {
|
||||||
@ -550,7 +570,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof 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.indexOf(curve) >= 0 ? curve : my.CURVE // 默认为 secp256k1
|
||||||
@ -582,7 +602,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @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 = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
if (this.isSeckey(seckey)) {
|
if (this.isSeckey(seckey)) {
|
||||||
/** @type {*} */
|
/** @type {*} */
|
||||||
@ -608,7 +628,7 @@ class TICrypto {
|
|||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
* position 就是通常所说的 PubKeyHash,出现在比特币交易的锁定脚本里
|
* position 就是通常所说的 PubKeyHash,出现在比特币交易的锁定脚本里
|
||||||
*/
|
*/
|
||||||
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 = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
if (this.isPubkey(pubkey)) {
|
if (this.isPubkey(pubkey)) {
|
||||||
@ -622,8 +642,14 @@ class TICrypto {
|
|||||||
.digest('hex')
|
.digest('hex')
|
||||||
.slice(-40)
|
.slice(-40)
|
||||||
} else {
|
} else {
|
||||||
let h256 = crypto.createHash('sha256').update(Buffer.from(pubkey, 'hex')).digest()
|
let h256 = crypto
|
||||||
let h160 = crypto.createHash('ripemd160').update(h256).digest('hex')
|
.createHash('sha256')
|
||||||
|
.update(Buffer.from(pubkey, 'hex'))
|
||||||
|
.digest()
|
||||||
|
let h160 = crypto
|
||||||
|
.createHash('ripemd160')
|
||||||
|
.update(h256)
|
||||||
|
.digest('hex')
|
||||||
return h160
|
return h160
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -639,7 +665,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof 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()
|
if (coin) coin = coin.toUpperCase()
|
||||||
coin = my.COIN_LIST.indexOf(coin) >= 0 ? coin : my.COIN
|
coin = my.COIN_LIST.indexOf(coin) >= 0 ? coin : my.COIN
|
||||||
@ -647,7 +673,9 @@ class TICrypto {
|
|||||||
if (coin === 'ETH') {
|
if (coin === 'ETH') {
|
||||||
// 对以太坊,按照 EIP55,把纯位置转换为大小写敏感能自我验证的hex地址。仍然为20节=40符。
|
// 对以太坊,按照 EIP55,把纯位置转换为大小写敏感能自我验证的hex地址。仍然为20节=40符。
|
||||||
position = position.toLowerCase().replace('0x', '')
|
position = position.toLowerCase().replace('0x', '')
|
||||||
let hash = keccak('keccak256').update(position).digest('hex')
|
let hash = keccak('keccak256')
|
||||||
|
.update(position)
|
||||||
|
.digest('hex')
|
||||||
address = '0x'
|
address = '0x'
|
||||||
for (var i = 0; i < position.length; i++) {
|
for (var i = 0; i < position.length; i++) {
|
||||||
if (parseInt(hash[i], 16) >= 8) {
|
if (parseInt(hash[i], 16) >= 8) {
|
||||||
@ -719,16 +747,19 @@ class TICrypto {
|
|||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
* 地址和PubKeyHash(即position)之间能互相转化
|
* 地址和PubKeyHash(即position)之间能互相转化
|
||||||
*/
|
*/
|
||||||
static address2position() {
|
static address2position () {
|
||||||
if (/^0x[\da-fA-F]{40}$/.test(address)) { // ETH
|
if (/^0x[\da-fA-F]{40}$/.test(address)) {
|
||||||
|
// ETH
|
||||||
// todo: 如果是大小写敏感的,进行有效性验证
|
// todo: 如果是大小写敏感的,进行有效性验证
|
||||||
return address.toLowerCase()
|
return address.toLowerCase()
|
||||||
} else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address)) { // BTC
|
} else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address)) {
|
||||||
|
// BTC
|
||||||
let hex = this.b58c_to_hex(address)
|
let hex = this.b58c_to_hex(address)
|
||||||
if (hex) {
|
if (hex) {
|
||||||
return hex.slice(2) // 去除网络前缀
|
return hex.slice(2) // 去除网络前缀
|
||||||
}
|
}
|
||||||
} else if (/^[Tt][0-9a-zA-Z\._]{31}$/.test(address)) { // TIC
|
} else if (/^[Tt][0-9a-zA-Z\._]{31}$/.test(address)) {
|
||||||
|
// TIC
|
||||||
// 格式合法
|
// 格式合法
|
||||||
let hex = this.b64t_to_hex(address)
|
let hex = this.b64t_to_hex(address)
|
||||||
let [all, prefix, position, checksum] = hex.match(/^([\da-fA-F]{2})([\da-fA-F]{40})([\da-fA-F]{6})$/)
|
let [all, prefix, position, checksum] = hex.match(/^([\da-fA-F]{2})([\da-fA-F]{40})([\da-fA-F]{6})$/)
|
||||||
@ -747,7 +778,7 @@ class TICrypto {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static isAddress(address) {
|
static isAddress (address) {
|
||||||
if (/^(0x)?[\da-fA-F]{40}$/.test(address)) {
|
if (/^(0x)?[\da-fA-F]{40}$/.test(address)) {
|
||||||
return 'ETH'
|
return 'ETH'
|
||||||
} else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address) && address.length !== 32) {
|
} else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address) && address.length !== 32) {
|
||||||
@ -776,7 +807,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof 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 = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin.toUpperCase() : my.COIN
|
||||||
return this.position2address(this.pubkey2position(pubkey, { coin }), { coin, world })
|
return this.position2address(this.pubkey2position(pubkey, { coin }), { coin, world })
|
||||||
@ -791,7 +822,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static secword2seed(secword, pass) {
|
static secword2seed (secword, pass) {
|
||||||
// 遵循bip39的算法。和 ether.HDNode.mnemonic2Seed 结果一样,是64字节的种子。
|
// 遵循bip39的算法。和 ether.HDNode.mnemonic2Seed 结果一样,是64字节的种子。
|
||||||
// 注意,bip39.mnemonicToSeedSync 也接受不合法的 secword,只要是个string,或者是 undefined/null/0/''/false(这几个的结果都一样)
|
// 注意,bip39.mnemonicToSeedSync 也接受不合法的 secword,只要是个string,或者是 undefined/null/0/''/false(这几个的结果都一样)
|
||||||
return bip39.mnemonicToSeedSync(secword, pass).toString('hex') // 结果一致与 new BitcoreMnemonic(secword).toSeed(pass).toString('hex') 或 ethers.HDNode.mnemonic2Seed(secword)。
|
return bip39.mnemonicToSeedSync(secword, pass).toString('hex') // 结果一致与 new BitcoreMnemonic(secword).toSeed(pass).toString('hex') 或 ethers.HDNode.mnemonic2Seed(secword)。
|
||||||
@ -805,7 +836,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof 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()
|
||||||
@ -849,7 +880,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomSeckey({ coin, tool } = {}) {
|
static randomSeckey ({ coin, tool } = {}) {
|
||||||
// 跳过 secword 直接产生随机密钥
|
// 跳过 secword 直接产生随机密钥
|
||||||
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin : my.COIN
|
coin = my.COIN_LIST.indexOf(coin?.toUpperCase()) >= 0 ? coin : my.COIN
|
||||||
if (tool === 'nacl') {
|
if (tool === 'nacl') {
|
||||||
@ -867,7 +898,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomKeypair({ tool, purpose } = {}) {
|
static randomKeypair ({ tool, purpose } = {}) {
|
||||||
let kp
|
let kp
|
||||||
if (tool === 'nacl') {
|
if (tool === 'nacl') {
|
||||||
if (purpose === 'encrypt') {
|
if (purpose === 'encrypt') {
|
||||||
@ -897,7 +928,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomAccount({ lang, coin, pass, path, tool, hasher } = {}) {
|
static randomAccount ({ lang, coin, pass, path, tool, hasher } = {}) {
|
||||||
let secword = this.randomSecword(lang)
|
let secword = this.randomSecword(lang)
|
||||||
return this.secword2account(secword, { coin, pass, path, tool, hasher })
|
return this.secword2account(secword, { coin, pass, path, tool, hasher })
|
||||||
}
|
}
|
||||||
@ -911,7 +942,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomString(length = 6, alphabet) {
|
static randomString (length = 6, alphabet) {
|
||||||
// 长度为 length,字母表为 alphabet 的随机字符串
|
// 长度为 length,字母表为 alphabet 的随机字符串
|
||||||
alphabet = alphabet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$%^&*@'
|
alphabet = alphabet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$%^&*@'
|
||||||
var text = ''
|
var text = ''
|
||||||
@ -929,7 +960,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomNumber({ length, min, max } = {}) {
|
static randomNumber ({ length, min, max } = {}) {
|
||||||
// 长度为 length 的随机数字,或者 (min||0) <= num < max
|
// 长度为 length 的随机数字,或者 (min||0) <= num < max
|
||||||
var num = 0
|
var num = 0
|
||||||
if (typeof length === 'number' && length > 0) {
|
if (typeof length === 'number' && length > 0) {
|
||||||
@ -955,7 +986,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static padStart(string, targetLength, symbol) {
|
static padStart (string, targetLength, symbol) {
|
||||||
// 2020-03: 发现在浏览器里,还不支持 string.padStart(),只好自己写个暂代。
|
// 2020-03: 发现在浏览器里,还不支持 string.padStart(),只好自己写个暂代。
|
||||||
let padLength = targetLength - string.length
|
let padLength = targetLength - string.length
|
||||||
for (let index = 1; index <= padLength; index++) {
|
for (let index = 1; index <= padLength; index++) {
|
||||||
@ -970,7 +1001,7 @@ class TICrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static randomUuid() {
|
static randomUuid () {
|
||||||
return uuid.v4()
|
return uuid.v4()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -983,7 +1014,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof 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.indexOf(hasher) >= 0 ? hasher : my.HASHER)
|
||||||
@ -1004,7 +1035,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static getMerkleRoot(todoHashList) {
|
static getMerkleRoot (todoHashList) {
|
||||||
//深拷贝传入数组,防止引用对象被改变
|
//深拷贝传入数组,防止引用对象被改变
|
||||||
let hashList = [...todoHashList]
|
let hashList = [...todoHashList]
|
||||||
if (!Array.isArray(hashList)) return null
|
if (!Array.isArray(hashList)) return null
|
||||||
@ -1041,11 +1072,14 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static distanceSig(hash, sig) {
|
static distanceSig (hash, sig) {
|
||||||
// hash为64hex字符,sig为128hex字符。返回用hex表达的距离。
|
// hash为64hex字符,sig为128hex字符。返回用hex表达的距离。
|
||||||
if (this.isSignature(sig) && this.isHash(hash)) {
|
if (this.isSignature(sig) && this.isHash(hash)) {
|
||||||
var hashSig = this.hash(sig) // 把签名也转成32字节的哈希,同样长度方便比较
|
var hashSig = this.hash(sig) // 把签名也转成32字节的哈希,同样长度方便比较
|
||||||
return new BigInt(hash, 16).subtract(new BigInt(hashSig, 16)).abs().toString(16)
|
return new BigInt(hash, 16)
|
||||||
|
.subtract(new BigInt(hashSig, 16))
|
||||||
|
.abs()
|
||||||
|
.toString(16)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -1060,7 +1094,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static compareSig(hash, sig1, sig2) {
|
static compareSig (hash, sig1, sig2) {
|
||||||
// 返回距离hash更近的sig
|
// 返回距离hash更近的sig
|
||||||
if (this.isHash(hash)) {
|
if (this.isHash(hash)) {
|
||||||
if (this.isSignature(sig2) && this.isSignature(sig1)) {
|
if (this.isSignature(sig2) && this.isSignature(sig1)) {
|
||||||
@ -1093,7 +1127,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static sortSigList(hash, sigList) {
|
static sortSigList (hash, sigList) {
|
||||||
if (Array.isArray(sigList) && this.isHash(hash)) {
|
if (Array.isArray(sigList) && this.isHash(hash)) {
|
||||||
sigList.sort(function (sig1, sig2) {
|
sigList.sort(function (sig1, sig2) {
|
||||||
if (this.isSignature(sig1) && this.isSignature(sig2)) {
|
if (this.isSignature(sig1) && this.isSignature(sig2)) {
|
||||||
@ -1117,7 +1151,7 @@ class TICrypto {
|
|||||||
* @param $para 需要拼接的数组,把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
|
* @param $para 需要拼接的数组,把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
|
||||||
* @return 拼接完成以后的字符串
|
* @return 拼接完成以后的字符串
|
||||||
*/
|
*/
|
||||||
static getString2Sign(paramSet, converter, delimiter) {
|
static getString2Sign (paramSet, converter, delimiter) {
|
||||||
if (paramSet && typeof paramSet === 'object') {
|
if (paramSet && typeof paramSet === 'object') {
|
||||||
var string2Sign = ''
|
var string2Sign = ''
|
||||||
var converter = converter || ''
|
var converter = converter || ''
|
||||||
@ -1152,7 +1186,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static rsaSign(string2Sign, prikey, signType) {
|
static rsaSign (string2Sign, prikey, signType) {
|
||||||
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
|
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
|
||||||
let signer = crypto.createSign(signType)
|
let signer = crypto.createSign(signType)
|
||||||
return encodeURIComponent(signer.update(string2Sign).sign(prikey, 'base64'))
|
return encodeURIComponent(signer.update(string2Sign).sign(prikey, 'base64'))
|
||||||
@ -1169,7 +1203,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static rsaVerify(string2Verify, signature, pubkey, signType) {
|
static rsaVerify (string2Verify, signature, pubkey, signType) {
|
||||||
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
|
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
|
||||||
let verifier = crypto.createVerify(signType)
|
let verifier = crypto.createVerify(signType)
|
||||||
return verifier.update(string2Verify).verify(pubkey, signature, 'base64')
|
return verifier.update(string2Verify).verify(pubkey, signature, 'base64')
|
||||||
@ -1183,7 +1217,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static buf_to_hex(buffer) {
|
static buf_to_hex (buffer) {
|
||||||
// buffer is an ArrayBuffer
|
// buffer is an ArrayBuffer
|
||||||
return Array.prototype.map.call(new Uint8Array(buffer), (x) => ('00' + x.toString(16)).slice(-2)).join('')
|
return Array.prototype.map.call(new Uint8Array(buffer), (x) => ('00' + x.toString(16)).slice(-2)).join('')
|
||||||
}
|
}
|
||||||
@ -1196,7 +1230,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static hex_to_buf(hex) {
|
static hex_to_buf (hex) {
|
||||||
return new Uint8Array(
|
return new Uint8Array(
|
||||||
hex.match(/[\da-f]{2}/gi).map(function (h) {
|
hex.match(/[\da-f]{2}/gi).map(function (h) {
|
||||||
return parseInt(h, 16)
|
return parseInt(h, 16)
|
||||||
@ -1215,7 +1249,7 @@ class TICrypto {
|
|||||||
* bs58check 和 bs58 可接受string, Buffer, ArrayBuffer, Array (包括空字符串'', 各种内容的数组例如包含 undefined,{...},等等);
|
* bs58check 和 bs58 可接受string, Buffer, ArrayBuffer, Array (包括空字符串'', 各种内容的数组例如包含 undefined,{...},等等);
|
||||||
* 不可接受 undefined, null, {...}, 等等,会返回 exception
|
* 不可接受 undefined, null, {...}, 等等,会返回 exception
|
||||||
*/
|
*/
|
||||||
static hex_to_b58c(hex) {
|
static hex_to_b58c (hex) {
|
||||||
try {
|
try {
|
||||||
return bs58check.encode(Buffer.from(hex, 'hex'))
|
return bs58check.encode(Buffer.from(hex, 'hex'))
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
@ -1223,7 +1257,7 @@ class TICrypto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static hex_to_b58(hex) {
|
static hex_to_b58 (hex) {
|
||||||
try {
|
try {
|
||||||
return bs58.encode(Buffer.from(hex, 'hex'))
|
return bs58.encode(Buffer.from(hex, 'hex'))
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
@ -1239,7 +1273,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static b58c_to_hex(box) {
|
static b58c_to_hex (box) {
|
||||||
try {
|
try {
|
||||||
return bs58check.decode(box).toString('hex')
|
return bs58check.decode(box).toString('hex')
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
@ -1247,7 +1281,7 @@ class TICrypto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static b58_to_hex(box) {
|
static b58_to_hex (box) {
|
||||||
try {
|
try {
|
||||||
return bs58.decode(box).toString('hex')
|
return bs58.decode(box).toString('hex')
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
@ -1263,11 +1297,14 @@ class TICrypto {
|
|||||||
* @param {*} b64
|
* @param {*} b64
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
static b64_to_b64t(b64='') {
|
static b64_to_b64t (b64 = '') {
|
||||||
return b64.replace(/\+/g, '.').replace(/\//g, '_').replace(/=/g, '')
|
return b64
|
||||||
|
.replace(/\+/g, '.')
|
||||||
|
.replace(/\//g, '_')
|
||||||
|
.replace(/=/g, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
static b64t_to_b64(b64t='') {
|
static b64t_to_b64 (b64t = '') {
|
||||||
return b64t.replace(/\./g, '+').replace(/_/g, '/')
|
return b64t.replace(/\./g, '+').replace(/_/g, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,7 +1316,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static hex_to_b64t(hex) {
|
static hex_to_b64t (hex) {
|
||||||
if (/^[0-9a-fA-F]+$/.test(hex)) {
|
if (/^[0-9a-fA-F]+$/.test(hex)) {
|
||||||
return this.b64_to_b64t(Buffer.from(hex, 'hex').toString('base64'))
|
return this.b64_to_b64t(Buffer.from(hex, 'hex').toString('base64'))
|
||||||
}
|
}
|
||||||
@ -1294,7 +1331,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static b64t_to_hex(b64t) {
|
static b64t_to_hex (b64t) {
|
||||||
if (/^[0-9a-zA-Z\._]+$/.test(b64t)) {
|
if (/^[0-9a-zA-Z\._]+$/.test(b64t)) {
|
||||||
return Buffer.from(this.b64t_to_b64(b64t), 'base64').toString('hex')
|
return Buffer.from(this.b64t_to_b64(b64t), 'base64').toString('hex')
|
||||||
}
|
}
|
||||||
@ -1302,25 +1339,25 @@ class TICrypto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Base32
|
// https://en.wikipedia.org/wiki/Base32
|
||||||
static hex_to_b32(hex, {encoding='RFC4648'}={}) {
|
static hex_to_b32 (hex, { encoding = 'RFC4648' } = {}) {
|
||||||
if (/^[0-9a-fA-F]+$/.test(hex)) {
|
if (/^[0-9a-fA-F]+$/.test(hex)) {
|
||||||
return base32encode(Buffer.from(hex, 'hex'), encoding)
|
return base32encode(Buffer.from(hex, 'hex'), encoding)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
static b32_to_hex(b32, {encoding='RFC4648'}={}) {
|
static b32_to_hex (b32, { encoding = 'RFC4648' } = {}) {
|
||||||
if (/^[A-Za-z2-7=]+$/.test(b32)) {
|
if (/^[A-Za-z2-7=]+$/.test(b32)) {
|
||||||
return Buffer.from(base32decode(b32.toUpperCase(), encoding)).toString('hex')
|
return Buffer.from(base32decode(b32.toUpperCase(), encoding)).toString('hex')
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
static hex_to_b32h(hex, {encoding='RFC4648-HEX'}={}) {
|
static hex_to_b32h (hex, { encoding = 'RFC4648-HEX' } = {}) {
|
||||||
if (/^[0-9a-fA-F]+$/.test(hex)) {
|
if (/^[0-9a-fA-F]+$/.test(hex)) {
|
||||||
return base32encode(Buffer.from(hex, 'hex'), encoding)
|
return base32encode(Buffer.from(hex, 'hex'), encoding)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
static b32h_to_hex(b32, {encoding='RFC4648-HEX'}={}) {
|
static b32h_to_hex (b32, { encoding = 'RFC4648-HEX' } = {}) {
|
||||||
if (/^[0-9A-Va-v=]+$/.test(b32)) {
|
if (/^[0-9A-Va-v=]+$/.test(b32)) {
|
||||||
return Buffer.from(base32decode(b32.toUpperCase(), encoding)).toString('hex')
|
return Buffer.from(base32decode(b32.toUpperCase(), encoding)).toString('hex')
|
||||||
}
|
}
|
||||||
@ -1335,10 +1372,12 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static hex_to_eip55(hex) {
|
static hex_to_eip55 (hex) {
|
||||||
if (/^(0x)?[\da-fA-F]+$/.test(hex)) {
|
if (/^(0x)?[\da-fA-F]+$/.test(hex)) {
|
||||||
hex = hex.toLowerCase().replace('0x', '')
|
hex = hex.toLowerCase().replace('0x', '')
|
||||||
let hash = keccak('keccak256').update(hex).digest('hex')
|
let hash = keccak('keccak256')
|
||||||
|
.update(hex)
|
||||||
|
.digest('hex')
|
||||||
let result = ''
|
let result = ''
|
||||||
for (var i = 0; i < hex.length; i++) {
|
for (var i = 0; i < hex.length; i++) {
|
||||||
if (parseInt(hash[i], 16) >= 8) {
|
if (parseInt(hash[i], 16) >= 8) {
|
||||||
@ -1360,7 +1399,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static compressPubkey(uncompressed) {
|
static compressPubkey (uncompressed) {
|
||||||
// test: https://iancoleman.io/bitcoin-key-compression/
|
// test: https://iancoleman.io/bitcoin-key-compression/
|
||||||
// compress: https://hacpai.com/article/1550844562914
|
// compress: https://hacpai.com/article/1550844562914
|
||||||
// 把 04xy 的非压缩公钥 转成 02x 或 03x 的压缩公钥
|
// 把 04xy 的非压缩公钥 转成 02x 或 03x 的压缩公钥
|
||||||
@ -1385,7 +1424,7 @@ class TICrypto {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof TICrypto
|
* @memberof TICrypto
|
||||||
*/
|
*/
|
||||||
static decompressPubkey(compressed) {
|
static decompressPubkey (compressed) {
|
||||||
// uncompress: https://stackoverflow.com/questions/17171542/algorithm-for-elliptic-curve-point-compression/53478265#53478265
|
// uncompress: https://stackoverflow.com/questions/17171542/algorithm-for-elliptic-curve-point-compression/53478265#53478265
|
||||||
// https://en.bitcoin.it/wiki/Secp256k1
|
// https://en.bitcoin.it/wiki/Secp256k1
|
||||||
// 把 02x 或 03x 的压缩公钥 转成 04xy 的非压缩公钥
|
// 把 02x 或 03x 的压缩公钥 转成 04xy 的非压缩公钥
|
||||||
@ -1394,13 +1433,73 @@ class TICrypto {
|
|||||||
const pIdent = new BigInt('3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c', 16) // prime.add(1).divide(4);
|
const pIdent = new BigInt('3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c', 16) // prime.add(1).divide(4);
|
||||||
var signY = new Number(compressed[1]) - 2
|
var signY = new Number(compressed[1]) - 2
|
||||||
var x = new BigInt(compressed.substr(2), 16)
|
var x = new BigInt(compressed.substr(2), 16)
|
||||||
var y = x.modPow(3, prime).add(7).mod(prime).modPow(pIdent, prime) // y mod p = +-(x^3 + 7)^((p+1)/4) mod p
|
var y = x
|
||||||
|
.modPow(3, prime)
|
||||||
|
.add(7)
|
||||||
|
.mod(prime)
|
||||||
|
.modPow(pIdent, prime) // y mod p = +-(x^3 + 7)^((p+1)/4) mod p
|
||||||
if (y.mod(2).toJSNumber() !== signY) {
|
if (y.mod(2).toJSNumber() !== signY) {
|
||||||
// If the parity doesn't match it's the *other* root
|
// If the parity doesn't match it's the *other* root
|
||||||
y = prime.subtract(y) // y = prime - y
|
y = prime.subtract(y) // y = prime - y
|
||||||
}
|
}
|
||||||
return '04' + this.padStart(x.toString(16), 64, '0') + this.padStart(y.toString(16), 64, '0')
|
return '04' + this.padStart(x.toString(16), 64, '0') + this.padStart(y.toString(16), 64, '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cid_to_cosh ({ cid }) {
|
||||||
|
if (/^[Q|1]/.test(cid)) {
|
||||||
|
return this.b58_to_hex(cid).slice(4)
|
||||||
|
} else if (/^b/.test(cid)) {
|
||||||
|
return this.b32_to_hex(cid.substr(1)).slice(8)
|
||||||
|
} else if (/^z/.test(cid)) {
|
||||||
|
return this.b58_to_hex(cid.substr(1)).slice(8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static cosh_to_cid ({ cosh, cidBase = 'b32', cidVersion = 1, cidCodec = 'raw', cidAlgo = 'sha256' }) {
|
||||||
|
const multibase = {
|
||||||
|
identity: 0x00,
|
||||||
|
b2: '0',
|
||||||
|
b8: '7',
|
||||||
|
b10: '9',
|
||||||
|
b16: 'f',
|
||||||
|
B16: 'F',
|
||||||
|
b32: 'b',
|
||||||
|
B32: 'B',
|
||||||
|
b32h: 'v',
|
||||||
|
B32h: 'V',
|
||||||
|
b36: 'k',
|
||||||
|
b64: 'm',
|
||||||
|
b64p: 'M',
|
||||||
|
b64u: 'u',
|
||||||
|
b64up: 'U',
|
||||||
|
b58: 'z',
|
||||||
|
}
|
||||||
|
const multicodec = {
|
||||||
|
dagpb: '70',
|
||||||
|
p2pkey: '72',
|
||||||
|
raw: '55'
|
||||||
|
}
|
||||||
|
const multialgo = {
|
||||||
|
identify: '00',
|
||||||
|
sha256: '12'
|
||||||
|
}
|
||||||
|
if (cidVersion === 0) {
|
||||||
|
return this.hex_to_b58(`${multialgo[cidAlgo]}${Number(cosh.length/2).toString(16)}${cosh}`)
|
||||||
|
}
|
||||||
|
if (cidVersion === 1) {
|
||||||
|
let fullHex = `01${multicodec[cidCodec]}${multialgo[cidAlgo]}${Number(cosh.length/2).toString(16)}${cosh}`
|
||||||
|
if (cidBase==='b32') {
|
||||||
|
return multibase[cidBase] + this.hex_to_b32(fullHex).toLowerCase().replace(/=/g,'')
|
||||||
|
}else if (cidBase==='b58') {
|
||||||
|
return multibase[cidBase] + this.hex_to_b58(fullHex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static string_to_raw_cid (str) {
|
||||||
|
return this.cosh_to_cid({ cosh: this.hash(str), cidVersion:1, cidCodec:'raw' })
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 必须单独写 module.exports,不要和类定义写在一起,否则会导致 jsdoc 解析不到类内文档。
|
// 必须单独写 module.exports,不要和类定义写在一起,否则会导致 jsdoc 解析不到类内文档。
|
||||||
|
Loading…
Reference in New Issue
Block a user