add: 通过 ethereum-rsa 实现了椭圆曲线公私钥加解密!fix: is_secword

This commit is contained in:
陆柯 2022-11-11 16:17:18 +08:00
parent c9b147aeaf
commit ec359d0d98
2 changed files with 101 additions and 60 deletions

View File

@ -10,6 +10,7 @@
"bip39": "^3.0.4", "bip39": "^3.0.4",
"bs58check": "^2.1.2", "bs58check": "^2.1.2",
"eccrypto-js": "^5.4.0", "eccrypto-js": "^5.4.0",
"ethereum-rsa": "^1.0.5",
"hdkey": "^2.0.1", "hdkey": "^2.0.1",
"js-crypto-key-utils": "^1.0.4", "js-crypto-key-utils": "^1.0.4",
"keccak": "^3.0.2", "keccak": "^3.0.2",

160
ticc.js
View File

@ -6,8 +6,9 @@ const bs58check = require('bs58check')
const bs58 = require('bs58') // bs58check depends on bs58 const bs58 = require('bs58') // bs58check depends on bs58
const uuid = require('uuid') const uuid = require('uuid')
const keccak = require('keccak') const keccak = require('keccak')
const eccrypto = require('eccrypto-js') // 用于加解密。eccrypto 在 windows 上和 openssl 的版本兼容性有点麻烦,所以换用 eccrypto-js const ecc = require('eccrypto-js') // 用于加解密。eccrypto 在 windows 上和 openssl 的版本兼容性有点麻烦,所以换用 eccrypto-js
const keyman = require('js-crypto-key-utils') // 转换原始密钥和 PER/DER 格式。 const keyman = require('js-crypto-key-utils') // 转换原始密钥和 PER/DER 格式。
const ethrsa = require('ethereum-rsa')
// const BitcoreMnemonic = require('bitcore-mnemonic') // https://bitcore.io/api/mnemonic/ https://github.com/bitpay/bitcore-mnemonic // 打包成 app 里常有问题,试图访问 window 变量,无法生成 secword // const BitcoreMnemonic = require('bitcore-mnemonic') // https://bitcore.io/api/mnemonic/ https://github.com/bitpay/bitcore-mnemonic // 打包成 app 里常有问题,试图访问 window 变量,无法生成 secword
const bip39 = require('bip39') // https://github.com/bitcoinjs/bip39 // 有更多语言,但不方便选择语言,也不能使用 pass const bip39 = require('bip39') // https://github.com/bitcoinjs/bip39 // 有更多语言,但不方便选择语言,也不能使用 pass
const hdkey = require('hdkey') // https://github.com/cryptocoinjs/hdkey // 或者用 bitcore-mnemonic 或者 ethers 里的相同功能 const hdkey = require('hdkey') // https://github.com/cryptocoinjs/hdkey // 或者用 bitcore-mnemonic 或者 ethers 里的相同功能
@ -123,7 +124,10 @@ class TicCrypto {
// return false // return false
//// for bip39. 注意bip39对当前defaultWordlist之外其他语言的合法 mnemonic 也返回 false这一点不如 bitcore-mnemonic. 所以不能直接 bip39.validateMnemonic(secword) //// for bip39. 注意bip39对当前defaultWordlist之外其他语言的合法 mnemonic 也返回 false这一点不如 bitcore-mnemonic. 所以不能直接 bip39.validateMnemonic(secword)
if (typeof secword === 'string' && !/(^\s)|\s\s|(\s$)/.test(secword) && [12, 15, 18, 21, 24].includes(secword.split(/\s+/).length)) { secword = secword
.replace(/^\s+/, '') // 删除开头的空格
.replace(/\s+$/, '') // 删除末尾的空格
if (typeof secword === 'string' && [12, 15, 18, 21, 24].includes(secword.split(/\s+/).length)) {
if (mode === 'easy') return true // easy模式不检查校验等等严格的合法性了反正 secword_to_seed 是接受一切字符串的 if (mode === 'easy') return true // easy模式不检查校验等等严格的合法性了反正 secword_to_seed 是接受一切字符串的
if (my.langMap[lang?.toLowerCase?.()]) { if (my.langMap[lang?.toLowerCase?.()]) {
// 指定了语言则针对该语言词库检查 // 指定了语言则针对该语言词库检查
@ -131,7 +135,9 @@ class TicCrypto {
} else { } else {
// 未指定语言则检查所有可能语言词库 // 未指定语言则检查所有可能语言词库
for (let lang of my.langList) { for (let lang of my.langList) {
return bip39.validateMnemonic(secword, bip39.wordlists[lang]) if (bip39.validateMnemonic(secword, bip39.wordlists[lang])) {
return true
}
} }
} }
} }
@ -208,35 +214,40 @@ class TicCrypto {
* *
* @static * @static
* @param {*} data * @param {*} data
* @param {*} option [{ tool, keytype, key, input, output, cipher }={}] * @param {*} option [{ mode, key, input, output, cipher }={}]
* @return {String} * @return {String}
* @memberof TicCrypto * @memberof TicCrypto
*/ */
static async encrypt_easy ({ data, tool = 'crypto', keytype = 'pwd', key, input = my.INPUT, output = my.OUTPUT, cipher = my.CIPHER } = {}) { static async encrypt_easy ({ data, mode = 'semkey', key, input = my.INPUT, output = my.OUTPUT, cipher = my.CIPHER } = {}) {
if (tool === 'eccrypto') { if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data)
if (mode === 'ethrsa') {
if (key?.prikey && key?.pubkey) {
return ethrsa.encryptMessage(data, key?.prikey, key?.pubkey)
} else {
return ethrsa.encryptMessage(data, key?.senderPrikey, key?.receiverPubkey)
}
} else if (mode === 'ecc') {
// data 应当是 utf8 的字符串。key 必须是 pubkey // data 应当是 utf8 的字符串。key 必须是 pubkey
// eccrypto 能用 Uint8Array 和 Buffer // eccrypto 能用 Uint8Array 和 Buffer
// eccrypto-js 只能用 Buffer // eccrypto-js 只能用 Buffer
// 在浏览器里 https://github.com/bitchan/eccrypto 库报错,即使用了 Uint8Array: Failed to execute 'encrypt' on 'SubtleCrypto': The provided value is not of type '(ArrayBuffer or ArrayBufferView)' // 在浏览器里 https://github.com/bitchan/eccrypto 库报错,即使用了 Uint8Array: Failed to execute 'encrypt' on 'SubtleCrypto': The provided value is not of type '(ArrayBuffer or ArrayBufferView)'
let cipherObject = await eccrypto.encrypt(Buffer.from(this.hex_to_buf(key)), data) let cipherObject = await ecc.encrypt(Buffer.from(this.hex_to_buf(key)), data)
return cipherObject // 返回一个复杂的结构 {iv:Buffer, ciphertext:Buffer, ...}。对同样的key和data每次返回的结果不一样 return cipherObject // 返回一个复杂的结构 {iv:Buffer, ciphertext:Buffer, ...}。对同样的key和data每次返回的结果不一样
} else if (keytype === 'pwd') { } else if (mode === 'semkey') {
// 对称加密 // 对称加密
if (typeof key === 'string') { let inputEncoding = input // 'utf8' by default, 'ascii', 'latin1' for string or ignored for Buffer/TypedArray/DataView
let inputEncoding = input // 'utf8' by default, 'ascii', 'latin1' for string or ignored for Buffer/TypedArray/DataView let outputEncoding = output === 'buf' ? undefined : output // 'latin1', 'base64', 'hex' by default or 'buf' to Buffer explicitly
let outputEncoding = output === 'buf' ? undefined : 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(cipher, this.hex_to_buf(this.hash_easy(key)), iv) // cipher 和 key 的长度必须相同,例如 cipher 是 ***-192那么 key 就必须是 192/8=24 字节 = 48 hex 的。
let encryptor = crypto.createCipheriv(cipher, this.hex_to_buf(this.hash_easy(key)), iv) // cipher 和 key 的长度必须相同,例如 cipher 是 ***-192那么 key 就必须是 192/8=24 字节 = 48 hex 的。 let ciphertext = encryptor.update(data, inputEncoding, outputEncoding)
if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data) ciphertext += encryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string
let ciphertext = encryptor.update(data, inputEncoding, outputEncoding) return { iv: iv.toString('hex'), ciphertext } // 有 iv显然每次结果不一样
ciphertext += encryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string } else if (mode === 'prikey') {
return { iv: iv.toString('hex'), ciphertext } // 有 iv显然每次结果不一样 // 只能用于 crypto.generateKeyPairSync('rsa') 生成的 rsa 公私钥,不能用于 Elliptic Curve 的公私钥
}
} else if (keytype === 'prikey') {
// 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeyPairSync('rsa') 生成的 rsa 公私钥
let prikeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 let prikeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
return crypto.privateEncrypt(prikeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。 return crypto.privateEncrypt(prikeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
} else if (keytype === 'pubkey') { } else if (mode === 'pubkey') {
// 只能用于 crypto.generateKeyPairSync('rsa') 生成的 rsa 公私钥,不能用于 Elliptic Curve 的公私钥
let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem')
return crypto.publicEncrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。 return crypto.publicEncrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。
} }
@ -248,39 +259,46 @@ class TicCrypto {
* *
* @static * @static
* @param {*} data * @param {*} data
* @param {Object} option [{ keytype, key, input, output, cipher, format }={}] * @param {Object} option [{ mode, key, input, output, cipher, format }={}]
* @return {String} * @return {String}
* @memberof TicCrypto * @memberof TicCrypto
*/ */
static async decrypt_easy ({ data = {}, tool = 'crypto', keytype = 'pwd', key, input = my.OUTPUT, output = my.OUTPUT, cipher = my.CIPHER } = {}) { static async decrypt_easy ({ data = {}, mode = 'semkey', key, input = my.OUTPUT, output = 'utf8', cipher = my.CIPHER } = {}) {
// data 应当是 encrypt 输出的数据类型 // data 应当是 encrypt 输出的数据类型
if (tool === 'eccrypto') { if (mode === 'ethrsa') {
if (key?.prikey && key?.pubkey) {
return ethrsa.decryptMessage(data, key?.prikey, key?.pubkey)
} else {
return ethrsa.decryptMessage(data, key?.receiverPrikey, key?.senderPubkey)
}
} else if (mode === 'ecc') {
try { try {
// eccrypto 只能接受 Buffer, 不接受 Uint8Array, 因为 eccrypto 需要调用 Buffer.compare 方法,不能在这里直接用 hex_to_buf // eccrypto 只能接受 Buffer, 不接受 Uint8Array, 因为 eccrypto 需要调用 Buffer.compare 方法,不能在这里直接用 hex_to_buf
// eccrypto 也只能接受 Buffer, 不接受 Uint8Array // eccrypto 也只能接受 Buffer, 不接受 Uint8Array
// data 需要是 eccrypto 自身encrypt方法返回的 cipherObject. key 是 private key。 // data 需要是 eccrypto 自身encrypt方法返回的 cipherObject. key 是 private key。
let plainbuffer = await eccrypto.decrypt(Buffer.from(key, 'hex'), data) // 返回的是 Buffer let plainbuffer = await ecc.decrypt(Buffer.from(key, 'hex'), data) // 返回的是 Buffer
return plainbuffer.toString('utf8') return plainbuffer.toString('utf8')
} catch (exception) { } catch (exception) {
// eccrypto 对无法解密的,会抛出异常 // eccrypto 对无法解密的,会抛出异常
return null return null
} }
} else if (keytype === 'pwd') { } else if (mode === 'semkey') {
// 对称解密 // 对称解密
if ((typeof data.ciphertext === 'string' || data.ciphertext instanceof Buffer) && typeof key === 'string') { if (typeof data.ciphertext === 'string' || data.ciphertext instanceof Buffer) {
let inputEncoding = input // input (=output of encrypt) could be 'latin1', 'base64', 'hex' by default for string or ignored for Buffer let inputEncoding = input // input (=output of encrypt) could be 'latin1', 'base64', 'hex' by default for string or ignored for Buffer
let outputEncoding = output === 'buf' ? undefined : output // output (=input of encrypt) could be 'latin1', 'ascii', 'utf8' by default or 'buf' to Buffer explicitly let outputEncoding = output === 'buf' ? undefined : output // output (=input of encrypt) could be 'latin1', 'ascii', 'utf8' by default or 'buf' to Buffer explicitly
let decryptor = crypto.createDecipheriv(cipher, this.hex_to_buf(this.hash_easy(key)), Buffer.from(data.iv, 'hex')) let decryptor = crypto.createDecipheriv(cipher, this.hex_to_buf(this.hash_easy(key)), Buffer.from(data.iv, 'hex'))
let decrypted = decryptor.update(data.ciphertext, inputEncoding, outputEncoding) let decrypted = decryptor.update(data.ciphertext, inputEncoding, outputEncoding)
decrypted += decryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string decrypted += decryptor.final(outputEncoding) // 但是 Buffer + Buffer 还是会变成string
// 如果用户输入错误密deciper也能解密无法自动判断是否正确结果。可在返回后人工判断。 // 如果用户输入错误密deciper也能解密无法自动判断是否正确结果。可在返回后人工判断。
return decrypted return decrypted
} }
} else if (keytype === 'prikey') { } else if (mode === 'prikey') {
// 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥 // 只能用于 crypto.generateKeyPairSync('rsa') 生成的 rsa 公私钥,不能用于 Elliptic Curve 的公私钥
let prikeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 let prikeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
return crypto.privateDecrypt(prikeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。 return crypto.privateDecrypt(prikeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
} else if (keytype === 'pubkey') { } else if (mode === 'pubkey') {
// 只能用于 crypto.generateKeyPairSync('rsa') 生成的 rsa 公私钥,不能用于 Elliptic Curve 的公私钥
let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem')
return crypto.publicDecrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。 return crypto.publicDecrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。
} }
@ -305,9 +323,9 @@ class TicCrypto {
let hashBuf = this.hash_easy(data, { output: 'buf' }) // 哈希必须输出为 buffer let hashBuf = this.hash_easy(data, { output: 'buf' }) // 哈希必须输出为 buffer
let signature = nacl.sign.detached(hashBuf, Buffer.from(prikey, 'hex')) let signature = nacl.sign.detached(hashBuf, Buffer.from(prikey, 'hex'))
return Buffer.from(signature).toString('hex') // 签名是64节128个hex字符 return Buffer.from(signature).toString('hex') // 签名是64节128个hex字符
} else if (tool === 'eccrypto' && prikey.length === 64) { } else if (tool === 'ecc' && prikey.length === 64) {
// eccrypto 对同一组data, prikey 生成的签名是固定的观察到hex长度为140或142是der格式。 // eccrypto 对同一组data, prikey 生成的签名是固定的观察到hex长度为140或142是der格式。
let signature = await eccrypto.sign(Buffer.from(prikey, 'hex'), this.hash_easy(data, { output: 'buf' })) let signature = await ecc.sign(Buffer.from(prikey, 'hex'), this.hash_easy(data, { output: 'buf' }))
return signature.toString('hex') return signature.toString('hex')
} else if (prikey.length === 64) { } else if (prikey.length === 64) {
// 纯 crypto // 纯 crypto
@ -343,10 +361,10 @@ class TicCrypto {
let bufPubkey = Buffer.from(pubkey, 'hex') let bufPubkey = Buffer.from(pubkey, 'hex')
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 ('ecc' === tool && signature.length >= 140) {
// 默认使用 eccrypto // 发现大小写不影响 eccrypto 验签!都能通过 // 默认使用 eccrypto // 发现大小写不影响 eccrypto 验签!都能通过
try { try {
let result = await eccrypto.verify(Buffer.from(pubkey, 'hex'), this.hash_easy(data, { output: 'buf' }), Buffer.from(signature, 'hex')) // 如果给signature添加1位hexeccrypto 的 verify结果也是true! 估计因为一位hex不被转成字节。 let result = await ecc.verify(Buffer.from(pubkey, 'hex'), this.hash_easy(data, { output: 'buf' }), Buffer.from(signature, 'hex')) // 如果给signature添加1位hexeccrypto 的 verify结果也是true! 估计因为一位hex不被转成字节。
return true return true
} catch (exception) { } catch (exception) {
// 对能够验证的eccrypto返回 null对无法验证的抛出异常 // 对能够验证的eccrypto返回 null对无法验证的抛出异常
@ -558,19 +576,20 @@ class TicCrypto {
static secword_to_account ({ secword, coin, coinFamily, world, pass, pathSeed, pathIndex, path, tool, hasher } = {}) { static secword_to_account ({ secword, coin, coinFamily, world, pass, pathSeed, pathIndex, path, tool, hasher } = {}) {
// account 比 keypair 多了 address 字段。 // account 比 keypair 多了 address 字段。
coin = coin?.toUpperCase?.() || my.COIN coin = coin?.toUpperCase?.() || my.COIN
coinFamily = coinFamily?.toUpperCase?.() || my.COIN_FAMILY
let kp = this.secword_to_keypair({ secword, coin, pass, pathSeed, pathIndex, path, tool, hasher }) let kp = this.secword_to_keypair({ secword, coin, pass, pathSeed, pathIndex, path, tool, hasher })
if (kp) { if (kp) {
if (coin === 'ETH') { if (coin === 'ETH' || coinFamily === 'ETH') {
world = world || 'mainnet' world = world || 'mainnet'
kp.address = this.pubkey_to_address({ pubkey: this.decompress_pubkey(kp.pubkey), coin, coinFamily, world }) kp.address = this.pubkey_to_address({ pubkey: this.decompress_pubkey(kp.pubkey), coin, coinFamily, world })
} else if (coin === 'BTC') { } else if (coin === 'BTC' || coinFamily === 'BTC') {
world = world || 'mainnet' world = world || 'mainnet'
kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, coinFamily, world }) kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, coinFamily, world })
} else { } else {
world = world || my.WORLD world = world || my.WORLD
kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, coinFamily, world }) kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, coinFamily, world })
} }
return { ...kp, coin, world, secword } return { ...kp, coin, coinFamily, world, secword }
} }
return null return null
} }
@ -1344,27 +1363,27 @@ class TicCrypto {
} }
// https://en.wikipedia.org/wiki/Base32 // https://en.wikipedia.org/wiki/Base32
static hex_to_b32 (hex, { encoding = 'RFC4648' } = {}) { static hex_to_b32 (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'), 'RFC4648')
} }
return null return null
} }
static b32_to_hex (b32, { encoding = 'RFC4648' } = {}) { static b32_to_hex (b32) {
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(), 'RFC4648')).toString('hex')
} }
return null return null
} }
static hex_to_b32h (hex, { encoding = 'RFC4648-HEX' } = {}) { static hex_to_b32h (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'), 'RFC4648-HEX')
} }
return null return null
} }
static b32h_to_hex (b32, { encoding = 'RFC4648-HEX' } = {}) { static b32h_to_hex (b32h) {
if (/^[0-9A-Va-v=]+$/.test(b32)) { if (/^[0-9A-Va-v=]+$/.test(b32h)) {
return Buffer.from(base32decode(b32.toUpperCase(), encoding)).toString('hex') return Buffer.from(base32decode(b32.toUpperCase(), 'RFC4648-HEX')).toString('hex')
} }
return null return null
} }
@ -1453,14 +1472,17 @@ class TicCrypto {
static cid_to_cosh ({ cid }) { static cid_to_cosh ({ cid }) {
if (/^[Q|1]/.test(cid)) { if (/^[Q|1]/.test(cid)) {
return this.b58_to_hex(cid).slice(4) return this.b58_to_hex(cid).slice(4)
} else if (/^b/.test(cid)) { } else if (/^[b|B]/.test(cid)) {
return this.b32_to_hex(cid.substr(1)).slice(8) return this.b32_to_hex(cid.substr(1)).slice(8)
} else if (/^z/.test(cid)) { } else if (/^z/.test(cid)) {
return this.b58_to_hex(cid.substr(1)).slice(8) return this.b58_to_hex(cid.substr(1)).slice(8)
} else if (/^[m|M|u|U]/.test(cid)) {
return Buffer.from(cid.substr(1), 'base64').toString('hex')
} }
} }
static cosh_to_cid ({ cosh, cidBase = 'b32', cidVersion = 1, cidCodec = 'raw', cidAlgo = 'sha256' }) { static cosh_to_cid ({ cosh, cidBase = 'b32', cidVersion = 1, cidCodec = 'raw', cidAlgo = 'sha256' }) {
// https://github.com/multiformats/multibase
const multibase = { const multibase = {
identity: 0x00, identity: 0x00,
b2: '0', b2: '0',
@ -1472,38 +1494,56 @@ class TicCrypto {
B32: 'B', B32: 'B',
b32h: 'v', b32h: 'v',
B32h: 'V', B32h: 'V',
b32hp: 't',
B32hp: 'T',
b32p: 'c',
B32p: 'C',
b32z: 'h', // base32z, z-base-32
b36: 'k', b36: 'k',
B36: 'K',
b64: 'm', b64: 'm',
b64p: 'M', b64p: 'M',
b64u: 'u', b64u: 'u',
b64up: 'U', b64up: 'U',
b58: 'z', b58: 'z',
} }
// https://github.com/multiformats/multicodec
const multicodec = { const multicodec = {
raw: '55',
dagpb: '70', dagpb: '70',
p2pkey: '72', p2pkey: '72',
raw: '55',
} }
const multialgo = { const multialgo = {
identify: '00', identify: '00',
sha256: '12', sha256: '12',
sha512: '13',
keccak256: '1b',
ripemd160: '1053',
md5: 'd5',
} }
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}`)
} } else if (cidVersion === 1) {
if (cidVersion === 1) { const 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}` let converted = ''
console.log(fullHex)
if (cidBase === 'b32') { if (cidBase === 'b32') {
return ( converted = this.hex_to_b32(fullHex)
multibase[cidBase] + .toLowerCase()
this.hex_to_b32(fullHex) .replace(/=/g, '')
.toLowerCase() } else if (cidBase === 'B32') {
.replace(/=/g, '') converted = this.hex_to_b32(fullHex)
) .toUpperCase()
.replace(/=/g, '')
} else if (cidBase === 'b58') { } else if (cidBase === 'b58') {
return multibase[cidBase] + this.hex_to_b58(fullHex) converted = this.hex_to_b58(fullHex)
} else if (cidBase === 'b64p') {
converted = Buffer.from(fullHex, 'hex').toString('base64')
} else if (cidBase === 'b64') {
converted = Buffer.from(fullHex, 'hex')
.toString('base64')
.replace(/=/g, '')
} }
return multibase[cidBase] + converted
} }
} }
} }