发现 BigInt=require('big-integer') 可能导致和原生 BigInt 的命名冲突,改为 bigint,同时把可以用原生 BigInt 的都用 BigInt。发现 /^[b|B]/ 这种写法会识别 |,改为 /^[bB]/

This commit is contained in:
Luk 2024-10-05 15:47:17 +08:00
parent 43b9bd6898
commit 40197b2905
2 changed files with 41 additions and 19 deletions

View File

@ -6,7 +6,7 @@
"dependencies": { "dependencies": {
"base32-decode": "^1.0.0", "base32-decode": "^1.0.0",
"base32-encode": "^1.2.0", "base32-encode": "^1.2.0",
"big-integer": "^1.6.51", "big-integer": "^1.6.52",
"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",

58
ticc.js
View File

@ -1,5 +1,5 @@
// const BigNumber=require('bignumber.js') // 处理整数 https://github.com/MikeMcl/bignumber.js // size: 360K // const bignum=require('bignumber.js') // 处理整数 https://github.com/MikeMcl/bignumber.js // size: 360K
const BigInt = require('big-integer') // 处理整数 https://github.com/peterolson/BigInteger.js // size: 188K. ethers.js 24M. const bigint = require('big-integer') // 处理整数 https://github.com/peterolson/BigInteger.js // size: 188K. ethers.js 24M. // 20241005 发现,在 node 控制台里,导入本库命名为 BigInt 后运行 BigInt(xxx) 会导致失败!因为现在已经有 JS 的新 primitive 也叫 BigInt, 不知道作为 server 运行时,怎么没有报错。改名为 bigint
const crypto = require('crypto') const crypto = require('crypto')
const nacl = require('tweetnacl') const nacl = require('tweetnacl')
const bs58check = require('bs58check') const bs58check = require('bs58check')
@ -536,12 +536,11 @@ class TicCrypto {
return `m/44'/60'/${path}` return `m/44'/60'/${path}`
} else if (coin === 'TIC') { } else if (coin === 'TIC') {
return `m/44'/60000'/${path}` return `m/44'/60000'/${path}`
} else if (coin === 'MATIC') { // Polygon 测试网 (Mumbai): 80001 } else if (coin === 'MATIC' || coin === 'POL') {
// Polygon 测试网 (Mumbai): 80001
return `m/44'/137'/${path}` return `m/44'/137'/${path}`
} else if (/[A-Z]{3}/.test(coin)) {
return `m/44'/60${this.alpha_to_digit(coin)}'/${path}`
} else { } else {
return '' return `m/44'/60${this.alpha_to_digit(coin)}'/${path}`
} }
} }
@ -1102,7 +1101,8 @@ class TicCrypto {
// hash为64hex字符sig为128hex字符。返回用hex表达的距离。 // hash为64hex字符sig为128hex字符。返回用hex表达的距离。
if (this.is_signature({ sig: sig }) && this.is_hash({ hash })) { if (this.is_signature({ sig: sig }) && this.is_hash({ hash })) {
var hashSig = this.hash_easy(sig) // 把签名也转成32字节的哈希同样长度方便比较 var hashSig = this.hash_easy(sig) // 把签名也转成32字节的哈希同样长度方便比较
return (new BigInt(hash, 16) - new BigInt(hashSig, 16)).toString(16).replace(/^-/, '') // if using bignumber.js: (BigInt('0x' + hash) - BigInt('0x' + hashSig)).toString(16) // 20241005 注意到,原来通过 require('big-integer') 进行直接减法,可能是错误的!换用原生 BigInt 配合直接减法。
return (BigInt('0x' + hash) - BigInt('0x' + hashSig)).toString(16).replace(/^-/, '') // if using bignumber.js: (bignum('0x' + hash) - bignum('0x' + hashSig)).toString(16)
} }
return null return null
} }
@ -1423,7 +1423,7 @@ class TicCrypto {
// 把 04xy 的非压缩公钥 转成 02x 或 03x 的压缩公钥 // 把 04xy 的非压缩公钥 转成 02x 或 03x 的压缩公钥
let [all, x, y] = uncompressed.toLowerCase().match(/^04(.{64})(.{64})$/) let [all, x, y] = uncompressed.toLowerCase().match(/^04(.{64})(.{64})$/)
let compressed let compressed
if (/[1,3,5,7,9,b,d,f]$/.test(y)) { if (/[13579bdf]$/.test(y)) {
compressed = '03' + x // y为奇数=>前缀03 compressed = '03' + x // y为奇数=>前缀03
} else { } else {
compressed = '02' + x // y为偶数=>前缀02 compressed = '02' + x // y为偶数=>前缀02
@ -1447,11 +1447,27 @@ class TicCrypto {
// https://en.bitcoin.it/wiki/Secp256k1 // https://en.bitcoin.it/wiki/Secp256k1
// 把 02x 或 03x 的压缩公钥 转成 04xy 的非压缩公钥 // 把 02x 或 03x 的压缩公钥 转成 04xy 的非压缩公钥
// Consts for secp256k1 curve. Adjust accordingly // Consts for secp256k1 curve. Adjust accordingly
const prime = new BigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16) // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 const prime = bigint('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16) // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
const pIdent = new BigInt('3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c', 16) // prime.add(1).divide(4); const pIdent = 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 = bigint(compressed.substr(2), 16)
// 需要用到 big-integer 的 modPow 方法。如果直接用原生的 BigInt 会 "Maximum BigInt size exceeded" // 需要用到 big-integer 的 modPow 方法。如果想用原生的 BigInt可以自己实现 modPow:
/*
function modPow(base, exponent, modulus) {
let result = BigInt(1);
base = BigInt(base);
while (exponent > 0n) {
if (exponent & BigInt(1)) {
result = (result * base) % modulus;
}
base = (base * base) % modulus;
exponent = exponent >> BigInt(1);
}
return result;
}
*/
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
@ -1462,16 +1478,18 @@ class TicCrypto {
// cosh: content hash. 最核心的纯hex的内容地址没有任何额外标记。同一个内容的cosh是唯一的而cid是在cosh基础上有各种不同的编码。cid建议叫做 coid. // cosh: content hash. 最核心的纯hex的内容地址没有任何额外标记。同一个内容的cosh是唯一的而cid是在cosh基础上有各种不同的编码。cid建议叫做 coid.
static cid_to_cosh ({ cid }) { static cid_to_cosh ({ cid }) {
if (/^[Q|1]/.test(cid)) { if (/^[Q1]/.test(cid)) {
return this.b58_to_hex(cid).slice(4) // 前2字节是 cid0 的字节序数标记 return this.b58_to_hex(cid).slice(4) // 前2字节是 cid0 的字节序数标记
} else if (/^[b|B]/.test(cid)) { } else if (/^[bB]/.test(cid)) {
return this.b32_to_hex(cid.substr(1)).slice(8) // 前4字节是 cid1 的标记 return this.b32_to_hex(cid.substr(1)).slice(8) // 前4字节是 cid1 的标记
} 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)) { } else if (/^[mMuU]/.test(cid)) {
return Buffer.from(cid.substr(1), 'base64').toString('hex') return Buffer.from(cid.substr(1), 'base64').toString('hex')
} else if (/^[fF]/) {
return cid.substr(9).toLowerCase()
} else if (/^9/.test(cid)) { } else if (/^9/.test(cid)) {
return new BigInt(cid.substr(1)).toString(16).slice(7) // BigInt toString(16) 后,去掉了 01551220... 的打头的 0所以只有7位需要跳过了 return BigInt(cid.slice(1)).toString(16).slice(7) // toString(16) 后,去掉了 01551220... 的打头的 0所以只有7位需要跳过了
} }
} }
@ -1520,7 +1538,11 @@ class TicCrypto {
} else if (cidVersion === 1) { } else if (cidVersion === 1) {
const fullHex = `01${multicodec[cidCodec]}${multialgo[cidAlgo]}${Number(cosh.length / 2).toString(16)}${cosh}` const fullHex = `01${multicodec[cidCodec]}${multialgo[cidAlgo]}${Number(cosh.length / 2).toString(16)}${cosh}`
let converted = '' let converted = ''
if (cidBase === 'b32') { if (cidBase === 'b16') {
converted = fullHex.toLowerCase()
} else if (cidBase === 'B16') {
converted = fullHex.toUpperCase()
} else if (cidBase === 'b32') {
converted = this.hex_to_b32(fullHex).toLowerCase().replace(/=/g, '') converted = this.hex_to_b32(fullHex).toLowerCase().replace(/=/g, '')
} else if (cidBase === 'B32') { } else if (cidBase === 'B32') {
converted = this.hex_to_b32(fullHex).toUpperCase().replace(/=/g, '') converted = this.hex_to_b32(fullHex).toUpperCase().replace(/=/g, '')
@ -1531,7 +1553,7 @@ class TicCrypto {
} else if (cidBase === 'b64') { } else if (cidBase === 'b64') {
converted = Buffer.from(fullHex, 'hex').toString('base64').replace(/=/g, '') converted = Buffer.from(fullHex, 'hex').toString('base64').replace(/=/g, '')
} else if (cidBase === 'b10') { } else if (cidBase === 'b10') {
converted = new BigInt(fullHex, 16).toString() converted = BigInt('0x' + fullHex).toString()
} }
return multibase[cidBase] + converted return multibase[cidBase] + converted
} }