sm-crypto-v2 0.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,267 @@
1
+ /* eslint-disable no-use-before-define */
2
+ import { BigInteger } from 'jsbn'
3
+ import { encodeDer, decodeDer } from './asn1'
4
+ import { arrayToHex, arrayToUtf8, concatArray, generateEcparam, generateKeyPairHex, getGlobalCurve, hexToArray, leftPad, utf8ToHex } from './utils'
5
+ import { sm3 } from './sm3'
6
+ export * from './utils'
7
+ const { G, curve, n } = generateEcparam()
8
+ const C1C2C3 = 0
9
+
10
+ /**
11
+ * 加密
12
+ */
13
+ export function doEncrypt(msg: string | Uint8Array, publicKey: string, cipherMode = 1) {
14
+
15
+ const msgArr = typeof msg === 'string' ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg)
16
+ const publicKeyPoint = getGlobalCurve().decodePointHex(publicKey) // 先将公钥转成点
17
+
18
+ const keypair = generateKeyPairHex()
19
+ const k = new BigInteger(keypair.privateKey, 16) // 随机数 k
20
+
21
+ // c1 = k * G
22
+ let c1 = keypair.publicKey
23
+ if (c1.length > 128) c1 = c1.substring(c1.length - 128)
24
+
25
+ // (x2, y2) = k * publicKey
26
+ const p = publicKeyPoint!.multiply(k)
27
+ const x2 = hexToArray(leftPad(p.getX().toBigInteger().toRadix(16), 64))
28
+ const y2 = hexToArray(leftPad(p.getY().toBigInteger().toRadix(16), 64))
29
+
30
+ // c3 = hash(x2 || msg || y2)
31
+ const c3 = arrayToHex(Array.from(sm3(concatArray(x2, msgArr, y2))));
32
+
33
+ let ct = 1
34
+ let offset = 0
35
+ let t: Uint8Array = new Uint8Array() // 256 位
36
+ const z = concatArray(x2, y2)
37
+ const nextT = () => {
38
+ // (1) Hai = hash(z || ct)
39
+ // (2) ct++
40
+ t = sm3(Uint8Array.from([...z, ct >> 24 & 0x00ff, ct >> 16 & 0x00ff, ct >> 8 & 0x00ff, ct & 0x00ff]))
41
+ ct++
42
+ offset = 0
43
+ }
44
+ nextT() // 先生成 Ha1
45
+
46
+ for (let i = 0, len = msgArr.length; i < len; i++) {
47
+ // t = Ha1 || Ha2 || Ha3 || Ha4
48
+ if (offset === t.length) nextT()
49
+
50
+ // c2 = msg ^ t
51
+ msgArr[i] ^= t[offset++] & 0xff
52
+ }
53
+ const c2 = arrayToHex(Array.from(msgArr))
54
+
55
+ return cipherMode === C1C2C3 ? c1 + c2 + c3 : c1 + c3 + c2
56
+ }
57
+
58
+ /**
59
+ * 解密
60
+ */
61
+ export function doDecrypt(encryptData: string, privateKey: string, cipherMode?: number, options?: {
62
+ output: 'array'
63
+ }): Uint8Array
64
+ export function doDecrypt(encryptData: string, privateKey: string, cipherMode?: number, options?: {
65
+ output: 'string'
66
+ }): string
67
+ export function doDecrypt(encryptData: string, privateKey: string, cipherMode = 1, {
68
+ output = 'string',
69
+ } = {}) {
70
+ const privateKeyInteger = new BigInteger(privateKey, 16)
71
+
72
+ let c3 = encryptData.substring(128, 128 + 64)
73
+ let c2 = encryptData.substring(128 + 64)
74
+
75
+ if (cipherMode === C1C2C3) {
76
+ c3 = encryptData.substring(encryptData.length - 64)
77
+ c2 = encryptData.substring(128, encryptData.length - 64)
78
+ }
79
+
80
+ const msg = hexToArray(c2)
81
+ const c1 = getGlobalCurve().decodePointHex('04' + encryptData.substring(0, 128))!
82
+
83
+ const p = c1.multiply(privateKeyInteger)
84
+ const x2 = hexToArray(leftPad(p.getX().toBigInteger().toRadix(16), 64))
85
+ const y2 = hexToArray(leftPad(p.getY().toBigInteger().toRadix(16), 64))
86
+ let ct = 1
87
+ let offset = 0
88
+ let t = new Uint8Array() // 256 位
89
+ const z = concatArray(x2, y2)
90
+ const nextT = () => {
91
+ // (1) Hai = hash(z || ct)
92
+ // (2) ct++
93
+ t = sm3(Uint8Array.from([...z, ct >> 24 & 0x00ff, ct >> 16 & 0x00ff, ct >> 8 & 0x00ff, ct & 0x00ff]))
94
+ ct++
95
+ offset = 0
96
+ }
97
+ nextT() // 先生成 Ha1
98
+
99
+ for (let i = 0, len = msg.length; i < len; i++) {
100
+ // t = Ha1 || Ha2 || Ha3 || Ha4
101
+ if (offset === t.length) nextT()
102
+
103
+ // c2 = msg ^ t
104
+ msg[i] ^= t[offset++] & 0xff
105
+ }
106
+ // c3 = hash(x2 || msg || y2)
107
+ const checkC3 = arrayToHex(Array.from(sm3(concatArray(x2, msg, y2))))
108
+
109
+ if (checkC3 === c3.toLowerCase()) {
110
+ return output === 'array' ? msg : arrayToUtf8(msg)
111
+ } else {
112
+ return output === 'array' ? [] : ''
113
+ }
114
+ }
115
+
116
+ export interface SignaturePoint {
117
+ k: BigInteger
118
+ x1: BigInteger
119
+ }
120
+
121
+ /**
122
+ * 签名
123
+ */
124
+ export function doSignature(msg: Uint8Array | string, privateKey: string, options: {
125
+ pointPool?: SignaturePoint[], der?: boolean, hash?: boolean, publicKey?: string, userId?: string
126
+ } = {}) {
127
+ let {
128
+ pointPool, der, hash, publicKey, userId
129
+ } = options
130
+ let hashHex = typeof msg === 'string' ? utf8ToHex(msg) : arrayToHex(Array.from(msg))
131
+
132
+ if (hash) {
133
+ // sm3杂凑
134
+ publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey)
135
+ hashHex = getHash(hashHex, publicKey, userId)
136
+ }
137
+
138
+ const dA = new BigInteger(privateKey, 16)
139
+ const e = new BigInteger(hashHex, 16)
140
+
141
+ // k
142
+ let k: BigInteger | null = null
143
+ let r: BigInteger | null = null
144
+ let s: BigInteger | null = null
145
+
146
+ do {
147
+ do {
148
+ let point: SignaturePoint
149
+ if (pointPool && pointPool.length) {
150
+ point = pointPool.pop()!
151
+ } else {
152
+ point = getPoint()
153
+ }
154
+ k = point.k
155
+
156
+ // r = (e + x1) mod n
157
+ r = e.add(point.x1).mod(n)
158
+ } while (r.equals(BigInteger.ZERO) || r.add(k).equals(n))
159
+
160
+ // s = ((1 + dA)^-1 * (k - r * dA)) mod n
161
+ s = dA.add(BigInteger.ONE).modInverse(n).multiply(k.subtract(r.multiply(dA))).mod(n)
162
+ } while (s.equals(BigInteger.ZERO))
163
+
164
+ if (der) return encodeDer(r, s) // asn.1 der 编码
165
+
166
+ return leftPad(r.toString(16), 64) + leftPad(s.toString(16), 64)
167
+ }
168
+
169
+ /**
170
+ * 验签
171
+ */
172
+ export function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string, options: { der?: boolean, hash?: boolean, userId?: string } = {}) {
173
+ let hashHex: string
174
+ const {
175
+ hash,
176
+ der,
177
+ userId,
178
+ } = options
179
+ if (hash) {
180
+ // sm3杂凑
181
+ hashHex = getHash(typeof msg === 'string' ? utf8ToHex(msg) : msg, publicKey, userId)
182
+ } else {
183
+ hashHex = typeof msg === 'string' ? utf8ToHex(msg) : arrayToHex(Array.from(msg))
184
+ }
185
+
186
+ let r: BigInteger;
187
+ let s: BigInteger;
188
+ if (der) {
189
+ const decodeDerObj = decodeDer(signHex) // asn.1 der 解码
190
+ r = decodeDerObj.r
191
+ s = decodeDerObj.s
192
+ } else {
193
+ r = new BigInteger(signHex.substring(0, 64), 16)
194
+ s = new BigInteger(signHex.substring(64), 16)
195
+ }
196
+
197
+ const PA = curve.decodePointHex(publicKey)!
198
+ const e = new BigInteger(hashHex, 16)
199
+
200
+ // t = (r + s) mod n
201
+ const t = r.add(s).mod(n)
202
+
203
+ if (t.equals(BigInteger.ZERO)) return false
204
+
205
+ // x1y1 = s * G + t * PA
206
+ const x1y1 = G.multiply(s).add(PA.multiply(t))
207
+
208
+ // R = (e + x1) mod n
209
+ const R = e.add(x1y1.getX().toBigInteger()).mod(n)
210
+
211
+ return r.equals(R)
212
+ }
213
+
214
+ /**
215
+ * sm3杂凑算法
216
+ */
217
+ export function getHash(hashHex: string | Uint8Array, publicKey: string, userId = '1234567812345678') {
218
+ // z = hash(entl || userId || a || b || gx || gy || px || py)
219
+ userId = utf8ToHex(userId)
220
+ const a = leftPad(G.curve.a.toBigInteger().toRadix(16), 64)
221
+ const b = leftPad(G.curve.b.toBigInteger().toRadix(16), 64)
222
+ const gx = leftPad(G.getX().toBigInteger().toRadix(16), 64)
223
+ const gy = leftPad(G.getY().toBigInteger().toRadix(16), 64)
224
+ let px: string
225
+ let py: string
226
+ if (publicKey.length === 128) {
227
+ px = publicKey.substring(0, 64)
228
+ py = publicKey.substring(64, 128)
229
+ } else {
230
+ const point = G.curve.decodePointHex(publicKey)!
231
+ px = leftPad(point.getX().toBigInteger().toRadix(16), 64)
232
+ py = leftPad(point.getY().toBigInteger().toRadix(16), 64)
233
+ }
234
+ const data = hexToArray(userId + a + b + gx + gy + px + py)
235
+
236
+ const entl = userId.length * 4
237
+
238
+ const z = sm3(concatArray(new Uint8Array([entl >> 8 & 0x00ff, entl & 0x00ff]), data))
239
+
240
+ // e = hash(z || msg)
241
+ return arrayToHex(Array.from(sm3(concatArray(z, typeof hashHex === 'string' ? hexToArray(hashHex) : hashHex))))
242
+ }
243
+
244
+ /**
245
+ * 计算公钥
246
+ */
247
+ export function getPublicKeyFromPrivateKey(privateKey: string) {
248
+ const PA = G.multiply(new BigInteger(privateKey, 16))
249
+ const x = leftPad(PA.getX().toBigInteger().toString(16), 64)
250
+ const y = leftPad(PA.getY().toBigInteger().toString(16), 64)
251
+ return '04' + x + y
252
+ }
253
+
254
+ /**
255
+ * 获取椭圆曲线点
256
+ */
257
+ export function getPoint() {
258
+ const keypair = generateKeyPairHex()
259
+ const PA = curve.decodePointHex(keypair.publicKey)
260
+
261
+ return {
262
+ ...keypair,
263
+ k: new BigInteger(keypair.privateKey, 16),
264
+ x1: PA!.getX().toBigInteger()
265
+ }
266
+ }
267
+
package/src/sm2/sm3.ts ADDED
@@ -0,0 +1,174 @@
1
+ import { concatArray } from './utils'
2
+
3
+ // 消息扩展
4
+ const W = new Uint32Array(68)
5
+ const M = new Uint32Array(64) // W'
6
+
7
+ /**
8
+ * 循环左移
9
+ */
10
+ export function rotl(x: number, n: number) {
11
+ const s = n & 31
12
+ return (x << s) | (x >>> (32 - s))
13
+ }
14
+
15
+ /**
16
+ * 二进制异或运算
17
+ */
18
+ function xor(x: Uint8Array, y: Uint8Array) {
19
+ const result = new Uint8Array(x.length)
20
+ for (let i = x.length - 1; i >= 0; i--) result[i] = (x[i] ^ y[i]) & 0xff
21
+ return result
22
+ }
23
+
24
+ /**
25
+ * 压缩函数中的置换函数 P0(X) = X xor (X <<< 9) xor (X <<< 17)
26
+ */
27
+ function P0(X: number) {
28
+ return (X ^ rotl(X, 9)) ^ rotl(X, 17)
29
+ }
30
+
31
+ /**
32
+ * 消息扩展中的置换函数 P1(X) = X xor (X <<< 15) xor (X <<< 23)
33
+ */
34
+ function P1(X: number) {
35
+ return (X ^ rotl(X, 15)) ^ rotl(X, 23)
36
+ }
37
+
38
+ /**
39
+ * sm3 本体
40
+ */
41
+ export function sm3(array: Uint8Array) {
42
+ let len = array.length * 8
43
+ // k 是满足 len + 1 + k = 448mod512 的最小的非负整数
44
+ let k = len % 512
45
+ // 如果 448 <= (512 % len) < 512,需要多补充 (len % 448) 比特'0'以满足总比特长度为512的倍数
46
+ k = k >= 448 ? 512 - (k % 448) - 1 : 448 - k - 1
47
+
48
+ // 填充
49
+ const kArr = new Array((k - 7) / 8)
50
+ const lenArr = new Array(8)
51
+ for (let i = 0, len = kArr.length; i < len; i++) kArr[i] = 0
52
+ for (let i = 0, len = lenArr.length; i < len; i++) lenArr[i] = 0
53
+ let lenString = len.toString(2)
54
+ for (let i = 7; i >= 0; i--) {
55
+ if (lenString.length > 8) {
56
+ const start = lenString.length - 8
57
+ lenArr[i] = parseInt(lenString.substring(start), 2)
58
+ lenString = lenString.substring(0, start)
59
+ } else if (lenString.length > 0) {
60
+ lenArr[i] = parseInt(lenString, 2)
61
+ lenString = ''
62
+ }
63
+ }
64
+ const m = Uint8Array.from([...array, 0x80, ...kArr, ...lenArr])
65
+ const dataView = new DataView(m.buffer, 0)
66
+
67
+ // 迭代压缩
68
+ const n = m.length / 64
69
+ const V = new Uint32Array([0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e])
70
+ for (let i = 0; i < n; i++) {
71
+ W.fill(0)
72
+ M.fill(0)
73
+
74
+ // 将消息分组B划分为 16 个字 W0, W1,……,W15
75
+ const start = 16 * i
76
+ for (let j = 0; j < 16; j++) {
77
+ W[j] = dataView.getUint32((start + j) * 4, false)
78
+ }
79
+
80
+ // W16 ~ W67:W[j] <- P1(W[j−16] xor W[j−9] xor (W[j−3] <<< 15)) xor (W[j−13] <<< 7) xor W[j−6]
81
+ for (let j = 16; j < 68; j++) {
82
+ W[j] = (P1((W[j - 16] ^ W[j - 9]) ^ rotl(W[j - 3], 15)) ^ rotl(W[j - 13], 7)) ^ W[j - 6]
83
+ }
84
+
85
+ // W′0 ~ W′63:W′[j] = W[j] xor W[j+4]
86
+ for (let j = 0; j < 64; j++) {
87
+ M[j] = W[j] ^ W[j + 4]
88
+ }
89
+
90
+ // 压缩
91
+ const T1 = 0x79cc4519
92
+ const T2 = 0x7a879d8a
93
+ // 字寄存器
94
+ let A = V[0]
95
+ let B = V[1]
96
+ let C = V[2]
97
+ let D = V[3]
98
+ let E = V[4]
99
+ let F = V[5]
100
+ let G = V[6]
101
+ let H = V[7]
102
+ // 中间变量
103
+ let SS1: number
104
+ let SS2: number
105
+ let TT1: number
106
+ let TT2: number
107
+ let T: number
108
+ for (let j = 0; j < 64; j++) {
109
+ T = j >= 0 && j <= 15 ? T1 : T2
110
+ SS1 = rotl(rotl(A, 12) + E + rotl(T, j), 7)
111
+ SS2 = SS1 ^ rotl(A, 12)
112
+
113
+ TT1 = (j >= 0 && j <= 15 ? ((A ^ B) ^ C) : (((A & B) | (A & C)) | (B & C))) + D + SS2 + M[j]
114
+ TT2 = (j >= 0 && j <= 15 ? ((E ^ F) ^ G) : ((E & F) | ((~E) & G))) + H + SS1 + W[j]
115
+
116
+ D = C
117
+ C = rotl(B, 9)
118
+ B = A
119
+ A = TT1
120
+ H = G
121
+ G = rotl(F, 19)
122
+ F = E
123
+ E = P0(TT2)
124
+ }
125
+
126
+ V[0] ^= A
127
+ V[1] ^= B
128
+ V[2] ^= C
129
+ V[3] ^= D
130
+ V[4] ^= E
131
+ V[5] ^= F
132
+ V[6] ^= G
133
+ V[7] ^= H
134
+ }
135
+
136
+ // 转回 uint8
137
+ const result = new Uint8Array(V.length * 4)
138
+ for (let i = 0, len = V.length; i < len; i++) {
139
+ const word = V[i]
140
+ result[i * 4] = (word & 0xff000000) >>> 24
141
+ result[i * 4 + 1] = (word & 0xff0000) >>> 16
142
+ result[i * 4 + 2] = (word & 0xff00) >>> 8
143
+ result[i * 4 + 3] = word & 0xff
144
+ }
145
+
146
+ return result
147
+ }
148
+
149
+ /**
150
+ * hmac 实现
151
+ */
152
+ const blockLen = 64
153
+ const iPad = new Uint8Array(blockLen)
154
+ const oPad = new Uint8Array(blockLen)
155
+ for (let i = 0; i < blockLen; i++) {
156
+ iPad[i] = 0x36
157
+ oPad[i] = 0x5c
158
+ }
159
+
160
+ export function hmac(input: Uint8Array, key: Uint8Array) {
161
+ // 密钥填充
162
+ if (key.length > blockLen) key = sm3(key)
163
+ while (key.length < blockLen) {
164
+ const padKey = new Uint8Array(blockLen)
165
+ padKey.set(key)
166
+ key = padKey
167
+ }
168
+
169
+ const iPadKey = xor(key, iPad)
170
+ const oPadKey = xor(key, oPad)
171
+
172
+ const hash = sm3(concatArray(iPadKey, input))
173
+ return sm3(concatArray(oPadKey, hash))
174
+ }
@@ -0,0 +1,208 @@
1
+ /* eslint-disable no-bitwise, no-mixed-operators, no-use-before-define, max-len */
2
+ import { BigInteger, RandomGenerator, SecureRandom } from 'jsbn'
3
+ import { ECCurveFp } from './ec'
4
+
5
+ declare module 'jsbn' {
6
+ export class SecureRandom implements RandomGenerator {
7
+ nextBytes(bytes: number[]): void;
8
+ }
9
+ }
10
+
11
+ const rng = new SecureRandom()
12
+ const {curve, G, n} = generateEcparam()
13
+
14
+ /**
15
+ * 获取公共椭圆曲线
16
+ */
17
+ export function getGlobalCurve() {
18
+ return curve
19
+ }
20
+
21
+ /**
22
+ * 生成ecparam
23
+ */
24
+ export function generateEcparam() {
25
+ // 椭圆曲线
26
+ const p = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16)
27
+ const a = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16)
28
+ const b = new BigInteger('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 16)
29
+ const curve = new ECCurveFp(p, a, b)
30
+
31
+ // 基点
32
+ const gxHex = '32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7'
33
+ const gyHex = 'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0'
34
+ const G = curve.decodePointHex('04' + gxHex + gyHex)!
35
+
36
+ const n = new BigInteger('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16)
37
+
38
+ return {curve, G, n}
39
+ }
40
+
41
+ /**
42
+ * 生成密钥对:publicKey = privateKey * G
43
+ */
44
+ export function generateKeyPairHex(a?: number | string, b?: number, c?: RandomGenerator) {
45
+ const random = typeof a === 'string' ? new BigInteger(a, b) :
46
+ a ? new BigInteger(a, b!, c!) : new BigInteger(n.bitLength(), rng)
47
+ const d = random.mod(n.subtract(BigInteger.ONE)).add(BigInteger.ONE) // 随机数
48
+ const privateKey = leftPad(d.toString(16), 64)
49
+
50
+ const P = G!.multiply(d) // P = dG,p 为公钥,d 为私钥
51
+ const Px = leftPad(P.getX().toBigInteger().toString(16), 64)
52
+ const Py = leftPad(P.getY().toBigInteger().toString(16), 64)
53
+ const publicKey = '04' + Px + Py
54
+ return {privateKey, publicKey}
55
+ }
56
+
57
+ /**
58
+ * 生成压缩公钥
59
+ */
60
+ export function compressPublicKeyHex(s: string) {
61
+ if (s.length !== 130) throw new Error('Invalid public key to compress')
62
+
63
+ const len = (s.length - 2) / 2
64
+ const xHex = s.substring(2, 2 + len)
65
+ const y = new BigInteger(s.substring(len + 2, len + len + 2), 16)
66
+
67
+ let prefix = '03'
68
+ if (y.mod(new BigInteger('2')).equals(BigInteger.ZERO)) prefix = '02'
69
+ return prefix + xHex
70
+ }
71
+
72
+ /**
73
+ * utf8串转16进制串
74
+ */
75
+ export function utf8ToHex(input: string) {
76
+ input = decodeURIComponent(encodeURIComponent(input))
77
+
78
+ const length = input.length
79
+
80
+ // 转换到字数组
81
+ const words = new Uint32Array((length >>> 2) + 1)
82
+ for (let i = 0; i < length; i++) {
83
+ words[i >>> 2] |= (input.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8)
84
+ }
85
+
86
+ // 转换到16进制
87
+ const hexChars: string[]= []
88
+ for (let i = 0; i < length; i++) {
89
+ const bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff
90
+ hexChars.push((bite >>> 4).toString(16))
91
+ hexChars.push((bite & 0x0f).toString(16))
92
+ }
93
+
94
+ return hexChars.join('')
95
+ }
96
+
97
+ /**
98
+ * 补全16进制字符串
99
+ */
100
+ export function leftPad(input: string, num: number) {
101
+ if (input.length >= num) return input
102
+
103
+ return (new Array(num - input.length + 1)).join('0') + input
104
+ }
105
+
106
+ /**
107
+ * 转成16进制串
108
+ */
109
+ export function arrayToHex(arr: number[]) {
110
+ return arr.map(item => {
111
+ const hex = item.toString(16)
112
+ return hex.length === 1 ? '0' + hex : hex
113
+ }).join('')
114
+ }
115
+
116
+ /**
117
+ * 转成utf8串
118
+ */
119
+ export function arrayToUtf8(arr: Uint8Array) {
120
+ const str: string[] = []
121
+ for (let i = 0, len = arr.length; i < len; i++) {
122
+ if (arr[i] >= 0xf0 && arr[i] <= 0xf7) {
123
+ // 四字节
124
+ str.push(String.fromCodePoint(((arr[i] & 0x07) << 18) + ((arr[i + 1] & 0x3f) << 12) + ((arr[i + 2] & 0x3f) << 6) + (arr[i + 3] & 0x3f)))
125
+ i += 3
126
+ } else if (arr[i] >= 0xe0 && arr[i] <= 0xef) {
127
+ // 三字节
128
+ str.push(String.fromCodePoint(((arr[i] & 0x0f) << 12) + ((arr[i + 1] & 0x3f) << 6) + (arr[i + 2] & 0x3f)))
129
+ i += 2
130
+ } else if (arr[i] >= 0xc0 && arr[i] <= 0xdf) {
131
+ // 双字节
132
+ str.push(String.fromCodePoint(((arr[i] & 0x1f) << 6) + (arr[i + 1] & 0x3f)))
133
+ i++
134
+ } else {
135
+ // 单字节
136
+ str.push(String.fromCodePoint(arr[i]))
137
+ }
138
+ }
139
+
140
+ return str.join('')
141
+ }
142
+
143
+ /**
144
+ * 转成字节数组
145
+ */
146
+ export function hexToArray(hexStr: string) {
147
+ let hexStrLength = hexStr.length
148
+
149
+ if (hexStrLength % 2 !== 0) {
150
+ hexStr = leftPad(hexStr, hexStrLength + 1)
151
+ }
152
+
153
+ hexStrLength = hexStr.length
154
+ const wordLength = hexStrLength / 2
155
+ const words = new Uint8Array(wordLength)
156
+
157
+ for (let i = 0; i < wordLength; i++) {
158
+ words[i] = (parseInt(hexStr.substring(i * 2, i * 2 + 2), 16))
159
+ }
160
+ return words
161
+ }
162
+
163
+ /**
164
+ * 验证公钥是否为椭圆曲线上的点
165
+ */
166
+ export function verifyPublicKey(publicKey: string) {
167
+ const point = curve.decodePointHex(publicKey)
168
+ if (!point) return false
169
+
170
+ const x = point.getX()
171
+ const y = point.getY()
172
+
173
+ // 验证 y^2 是否等于 x^3 + ax + b
174
+ return y.square().equals(x.multiply(x.square()).add(x.multiply(curve.a)).add(curve.b))
175
+ }
176
+
177
+ /**
178
+ * 验证公钥是否等价,等价返回true
179
+ */
180
+ export function comparePublicKeyHex(publicKey1: string, publicKey2: string) {
181
+ const point1 = curve.decodePointHex(publicKey1)
182
+ if (!point1) return false
183
+
184
+ const point2 = curve.decodePointHex(publicKey2)
185
+ if (!point2) return false
186
+
187
+ return point1.equals(point2)
188
+ }
189
+
190
+
191
+ export function concatArray(...arrays: Uint8Array[]) {
192
+ // sum of individual array lengths
193
+ let totalLength = arrays.reduce((acc, value) => acc + value.length, 0);
194
+
195
+ if (!arrays.length) return new Uint8Array();
196
+
197
+ let result = new Uint8Array(totalLength);
198
+
199
+ // for each array - copy it over result
200
+ // next array is copied right after the previous one
201
+ let length = 0;
202
+ for (let array of arrays) {
203
+ result.set(array, length);
204
+ length += array.length;
205
+ }
206
+
207
+ return result;
208
+ }