添加 cid 转换函数
This commit is contained in:
parent
447a3eb442
commit
74694866bc
125
index.js
125
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\._]+$/,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -164,7 +175,10 @@ class TICrypto {
|
|||||||
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
|
||||||
}
|
}
|
||||||
@ -349,7 +363,10 @@ class TICrypto {
|
|||||||
// 如果使用其他机制,例如密码、随机数,不使用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'),
|
||||||
@ -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,
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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) {
|
||||||
@ -720,15 +748,18 @@ class 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})$/)
|
||||||
@ -1045,7 +1076,10 @@ class TICrypto {
|
|||||||
// 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
|
||||||
}
|
}
|
||||||
@ -1264,7 +1298,10 @@ class TICrypto {
|
|||||||
* @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 = '') {
|
||||||
@ -1338,7 +1375,9 @@ class 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) {
|
||||||
@ -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