sm-crypto-v2 0.3.13 → 1.2.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sm-crypto-v2",
3
- "version": "0.3.13",
3
+ "version": "1.2.0",
4
4
  "description": "sm-crypto-v2",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -8,10 +8,10 @@
8
8
  "scripts": {
9
9
  "prepublish": "npm run build",
10
10
  "lint": "eslint \"src/**/*.js\" --fix",
11
- "build": "tsup",
11
+ "build": "vitest run && tsup",
12
12
  "watch": "tsup --watch",
13
13
  "test": "vitest",
14
- "release": "vitest run && standard-version && git push --follow-tags origin master",
14
+ "release": "npm run build && standard-version && git push --follow-tags origin master",
15
15
  "coverage": "vitest run --coverage"
16
16
  },
17
17
  "repository": {
@@ -30,8 +30,8 @@
30
30
  "author": "june_01",
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@types/jsbn": "^1.2.30",
34
- "jsbn": "^1.1.0"
33
+ "@noble/curves": "^1.1.0",
34
+ "@types/jsbn": "^1.2.30"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@swc/core": "^1.3.62",
package/pnpm-lock.yaml CHANGED
@@ -1,12 +1,12 @@
1
1
  lockfileVersion: '6.0'
2
2
 
3
3
  dependencies:
4
+ '@noble/curves':
5
+ specifier: ^1.1.0
6
+ version: 1.1.0
4
7
  '@types/jsbn':
5
8
  specifier: ^1.2.30
6
9
  version: 1.2.30
7
- jsbn:
8
- specifier: ^1.1.0
9
- version: 1.1.0
10
10
 
11
11
  devDependencies:
12
12
  '@swc/core':
@@ -581,6 +581,17 @@ packages:
581
581
  '@jridgewell/sourcemap-codec': 1.4.14
582
582
  dev: true
583
583
 
584
+ /@noble/curves@1.1.0:
585
+ resolution: {integrity: sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==}
586
+ dependencies:
587
+ '@noble/hashes': 1.3.1
588
+ dev: false
589
+
590
+ /@noble/hashes@1.3.1:
591
+ resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==}
592
+ engines: {node: '>= 16'}
593
+ dev: false
594
+
584
595
  /@nodelib/fs.scandir@2.1.5:
585
596
  resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
586
597
  engines: {node: '>= 8'}
@@ -2480,10 +2491,6 @@ packages:
2480
2491
  argparse: 2.0.1
2481
2492
  dev: true
2482
2493
 
2483
- /jsbn@1.1.0:
2484
- resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
2485
- dev: false
2486
-
2487
2494
  /jsesc@2.5.2:
2488
2495
  resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
2489
2496
  engines: {node: '>=4'}
package/src/sm2/asn1.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  /* eslint-disable class-methods-use-this */
2
2
 
3
- import { BigInteger } from 'jsbn'
3
+ import * as utils from '@noble/curves/abstract/utils';
4
+ import { ONE } from './bn';
4
5
 
5
- export function bigintToValue(bigint: BigInteger) {
6
+ export function bigintToValue(bigint: bigint) {
6
7
  let h = bigint.toString(16)
7
8
  if (h[0] !== '-') {
8
9
  // 正数
@@ -10,18 +11,18 @@ export function bigintToValue(bigint: BigInteger) {
10
11
  else if (!h.match(/^[0-7]/)) h = '00' + h // 非0开头,则补一个全0字节
11
12
  } else {
12
13
  // 负数
13
- h = h.substr(1)
14
-
14
+ h = h.substring(1)
15
15
  let len = h.length
16
16
  if (len % 2 === 1) len += 1 // 补齐到整字节
17
17
  else if (!h.match(/^[0-7]/)) len += 2 // 非0开头,则补一个全0字节
18
18
 
19
19
  let maskString = ''
20
20
  for (let i = 0; i < len; i++) maskString += 'f'
21
- let mask = new BigInteger(maskString, 16)
21
+ let mask = utils.hexToNumber(maskString)
22
22
 
23
23
  // 对绝对值取反,加1
24
- let output = mask.xor(bigint).add(BigInteger.ONE)
24
+
25
+ let output = (mask ^ bigint) + ONE
25
26
  h = output.toString(16).replace(/^-/, '')
26
27
  }
27
28
  return h
@@ -68,7 +69,7 @@ class ASN1Object {
68
69
  }
69
70
 
70
71
  class DERInteger extends ASN1Object {
71
- constructor(bigint: BigInteger) {
72
+ constructor(bigint: bigint) {
72
73
  super()
73
74
 
74
75
  this.t = '02' // 整型标签说明
@@ -109,9 +110,9 @@ function getL(str: string, start: number) {
109
110
  const l = str.substring(start + 2, start + 2 + len * 2)
110
111
 
111
112
  if (!l) return -1
112
- const bigint = +l[0] < 8 ? new BigInteger(l, 16) : new BigInteger(l.substring(2), 16)
113
+ const bigint = +l[0] < 8 ? utils.hexToNumber(l): utils.hexToNumber(l.substring(2))
113
114
 
114
- return bigint.intValue()
115
+ return +bigint.toString()
115
116
  }
116
117
 
117
118
  /**
@@ -125,7 +126,7 @@ function getStartOfV(str: string, start: number) {
125
126
  /**
126
127
  * ASN.1 der 编码,针对 sm2 签名
127
128
  */
128
- export function encodeDer(r: BigInteger, s: BigInteger) {
129
+ export function encodeDer(r: bigint, s: bigint) {
129
130
  const derR = new DERInteger(r)
130
131
  const derS = new DERInteger(s)
131
132
  const derSeq = new DERSequence([derR, derS])
@@ -151,8 +152,10 @@ export function decodeDer(input: string) {
151
152
  const lS = getL(input, nextStart)
152
153
  const vS = input.substring(vIndexS, vIndexS + lS * 2)
153
154
 
154
- const r = new BigInteger(vR, 16)
155
- const s = new BigInteger(vS, 16)
155
+ // const r = new BigInteger(vR, 16)
156
+ // const s = new BigInteger(vS, 16)
157
+ const r = utils.hexToNumber(vR)
158
+ const s = utils.hexToNumber(vS)
156
159
 
157
160
  return { r, s }
158
161
  }
package/src/sm2/bn.ts ADDED
@@ -0,0 +1,4 @@
1
+ export const ZERO = BigInt(0);
2
+ export const ONE = BigInt(1);
3
+ export const TWO = BigInt(2);
4
+ export const THREE = BigInt(3);
package/src/sm2/ec.ts CHANGED
@@ -1,333 +1,95 @@
1
- /* eslint-disable no-case-declarations, max-len */
2
-
3
- import { BigInteger } from 'jsbn'
4
-
5
- /**
6
- * thanks for Tom Wu : http://www-cs-students.stanford.edu/~tjw/jsbn/
7
- *
8
- * Basic Javascript Elliptic Curve implementation
9
- * Ported loosely from BouncyCastle's Java EC code
10
- * Only Fp curves implemented for now
11
- */
12
-
13
- const TWO = new BigInteger('2')
14
- const THREE = new BigInteger('3')
1
+ import { weierstrass } from '@noble/curves/abstract/weierstrass';
2
+ import { Field } from '@noble/curves/abstract/modular'; // finite field for mod arithmetics
3
+ import { hmac, sm3 } from './sm3'
4
+ import { utf8ToArray } from '@/sm3';
5
+ import { concatArray } from './utils';
6
+ import { ONE } from './bn';
15
7
 
16
8
  /**
17
- * 椭圆曲线域元素
9
+ * 安全随机数发生器
10
+ * 如果有原生同步接口,直接使用。否则维护一个随机数池,使用异步接口实现。
11
+ * Web: webcrypto 原生同步接口
12
+ * Node: Node v18 之前需要引入 crypto 模块,这里使用异步 import
13
+ * 小程序:异步接口
18
14
  */
19
- class ECFieldElementFp {
20
- constructor(public q: BigInteger, public x: BigInteger) {
21
- // TODO if (x.compareTo(q) >= 0) error
22
- }
23
-
24
- /**
25
- * 判断相等
26
- */
27
- equals(other: ECFieldElementFp) {
28
- if (other === this) return true
29
- return (this.q.equals(other.q) && this.x.equals(other.x))
30
- }
31
-
32
- /**
33
- * 返回具体数值
34
- */
35
- toBigInteger() {
36
- return this.x
37
- }
38
-
39
- /**
40
- * 取反
41
- */
42
- negate() {
43
- return new ECFieldElementFp(this.q, this.x.negate().mod(this.q))
44
- }
45
-
46
- /**
47
- * 相加
48
- */
49
- add(b) {
50
- return new ECFieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q))
51
- }
52
-
53
- /**
54
- * 相减
55
- */
56
- subtract(b) {
57
- return new ECFieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q))
58
- }
59
-
60
- /**
61
- * 相乘
62
- */
63
- multiply(b) {
64
- return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q))
65
- }
66
-
67
- /**
68
- * 相除
69
- */
70
- divide(b) {
71
- return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q))
72
- }
73
-
74
- /**
75
- * 平方
76
- */
77
- square() {
78
- return new ECFieldElementFp(this.q, this.x.square().mod(this.q))
79
- }
15
+ declare module wx {
16
+ function getRandomValues(options: {
17
+ length: number;
18
+ success: (res: { randomValues: ArrayBuffer }) => void;
19
+ }): void;
80
20
  }
81
21
 
82
- class ECPointFp {
83
- zinv: BigInteger | null
84
- z: BigInteger
85
- constructor(public curve: ECCurveFp, public x: ECFieldElementFp | null, public y: ECFieldElementFp | null, z?: BigInteger) {
86
- // 标准射影坐标系:zinv == null z * zinv == 1
87
- this.z = z == null ? BigInteger.ONE : z
88
- this.zinv = null
89
- // TODO: compression flag
90
- }
91
-
92
- getX() {
93
- if (this.zinv === null) this.zinv = this.z.modInverse(this.curve.q)
94
-
95
- return this.curve.fromBigInteger(this.x!.toBigInteger().multiply(this.zinv).mod(this.curve.q))
96
- }
97
-
98
- getY() {
99
- if (this.zinv === null) this.zinv = this.z.modInverse(this.curve.q)
100
-
101
- return this.curve.fromBigInteger(this.y!.toBigInteger().multiply(this.zinv).mod(this.curve.q))
102
- }
103
-
104
- /**
105
- * 判断相等
106
- */
107
- equals(other: ECPointFp) {
108
- if (other === this) return true
109
- if (this.isInfinity()) return other.isInfinity()
110
- if (other.isInfinity()) return this.isInfinity()
111
-
112
- // u = y2 * z1 - y1 * z2
113
- const u = other.y!.toBigInteger().multiply(this.z).subtract(this.y!.toBigInteger().multiply(other.z)).mod(this.curve.q)
114
- if (!u.equals(BigInteger.ZERO)) return false
115
-
116
- // v = x2 * z1 - x1 * z2
117
- const v = other.x!.toBigInteger().multiply(this.z).subtract(this.x!.toBigInteger().multiply(other.z)).mod(this.curve.q)
118
- return v.equals(BigInteger.ZERO)
119
- }
120
-
121
- /**
122
- * 是否是无穷远点
123
- */
124
- isInfinity() {
125
- if ((this.x === null) && (this.y === null)) return true
126
- return this.z.equals(BigInteger.ZERO) && !this.y!.toBigInteger().equals(BigInteger.ZERO)
127
- }
128
-
129
- /**
130
- * 取反,x 轴对称点
131
- */
132
- negate() {
133
- return new ECPointFp(this.curve, this.x, this.y!.negate(), this.z)
134
- }
135
-
136
- /**
137
- * 相加
138
- *
139
- * 标准射影坐标系:
140
- *
141
- * λ1 = x1 * z2
142
- * λ2 = x2 * z1
143
- * λ3 = λ1 − λ2
144
- * λ4 = y1 * z2
145
- * λ5 = y2 * z1
146
- * λ6 = λ4 − λ5
147
- * λ7 = λ1 + λ2
148
- * λ8 = z1 * z2
149
- * λ9 = λ3^2
150
- * λ10 = λ3 * λ9
151
- * λ11 = λ8 * λ6^2 − λ7 * λ9
152
- * x3 = λ3 * λ11
153
- * y3 = λ6 * (λ9 * λ1 − λ11) − λ4 * λ10
154
- * z3 = λ10 * λ8
155
- */
156
- add(b: ECPointFp) {
157
- if (this.isInfinity()) return b
158
- if (b.isInfinity()) return this
159
-
160
- const x1 = this.x!.toBigInteger()
161
- const y1 = this.y!.toBigInteger()
162
- const z1 = this.z
163
- const x2 = b.x!.toBigInteger()
164
- const y2 = b.y!.toBigInteger()
165
- const z2 = b.z
166
- const q = this.curve.q
167
-
168
- const w1 = x1.multiply(z2).mod(q)
169
- const w2 = x2.multiply(z1).mod(q)
170
- const w3 = w1.subtract(w2)
171
- const w4 = y1.multiply(z2).mod(q)
172
- const w5 = y2.multiply(z1).mod(q)
173
- const w6 = w4.subtract(w5)
174
-
175
- if (BigInteger.ZERO.equals(w3)) {
176
- if (BigInteger.ZERO.equals(w6)) {
177
- return this.twice() // this == b,计算自加
178
- }
179
- return this.curve.infinity // this == -b,则返回无穷远点
180
- }
181
-
182
- const w7 = w1.add(w2)
183
- const w8 = z1.multiply(z2).mod(q)
184
- const w9 = w3.square().mod(q)
185
- const w10 = w3.multiply(w9).mod(q)
186
- const w11 = w8.multiply(w6.square()).subtract(w7.multiply(w9)).mod(q)
187
-
188
- const x3 = w3.multiply(w11).mod(q)
189
- const y3 = w6.multiply(w9.multiply(w1).subtract(w11)).subtract(w4.multiply(w10)).mod(q)
190
- const z3 = w10.multiply(w8).mod(q)
191
-
192
- return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3)
193
- }
194
-
195
- /**
196
- * 自加
197
- *
198
- * 标准射影坐标系:
199
- *
200
- * λ1 = 3 * x1^2 + a * z1^2
201
- * λ2 = 2 * y1 * z1
202
- * λ3 = y1^2
203
- * λ4 = λ3 * x1 * z1
204
- * λ5 = λ2^2
205
- * λ6 = λ1^2 − 8 * λ4
206
- * x3 = λ2 * λ6
207
- * y3 = λ1 * (4 * λ4 − λ6) − 2 * λ5 * λ3
208
- * z3 = λ2 * λ5
209
- */
210
- twice() {
211
- if (this.isInfinity()) return this
212
- if (!this.y!.toBigInteger().signum()) return this.curve.infinity
213
-
214
- const x1 = this.x!.toBigInteger()
215
- const y1 = this.y!.toBigInteger()
216
- const z1 = this.z
217
- const q = this.curve.q
218
- const a = this.curve.a.toBigInteger()
219
-
220
- const w1 = x1.square().multiply(THREE).add(a.multiply(z1.square())).mod(q)
221
- const w2 = y1.shiftLeft(1).multiply(z1).mod(q)
222
- const w3 = y1.square().mod(q)
223
- const w4 = w3.multiply(x1).multiply(z1).mod(q)
224
- const w5 = w2.square().mod(q)
225
- const w6 = w1.square().subtract(w4.shiftLeft(3)).mod(q)
226
-
227
- const x3 = w2.multiply(w6).mod(q)
228
- const y3 = w1.multiply(w4.shiftLeft(2).subtract(w6)).subtract(w5.shiftLeft(1).multiply(w3)).mod(q)
229
- const z3 = w2.multiply(w5).mod(q)
230
-
231
- return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3)
232
- }
233
-
234
- /**
235
- * 倍点计算
236
- */
237
- multiply(k: BigInteger) {
238
- if (this.isInfinity()) return this
239
- if (!k.signum()) return this.curve.infinity
240
-
241
- // 使用加减法
242
- const k3 = k.multiply(THREE)
243
- const neg = this.negate()
244
- let Q: ECPointFp = this
245
-
246
- for (let i = k3.bitLength() - 2; i > 0; i--) {
247
- Q = Q.twice()
248
-
249
- const k3Bit = k3.testBit(i)
250
- const kBit = k.testBit(i)
251
-
252
- if (k3Bit !== kBit) {
253
- Q = Q.add(k3Bit ? this : neg)
254
- }
22
+ const DEFAULT_PRNG_POOL_SIZE = 4096
23
+ let prngPool = new Uint8Array(DEFAULT_PRNG_POOL_SIZE)
24
+
25
+ async function FillPRNGPoolIfNeeded() {
26
+ if ('crypto' in globalThis) return // no need to use pooling
27
+ if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2) return // there is sufficient number
28
+ // we always populate full pool size
29
+ // since numbers may be consumed during micro tasks.
30
+ if ('wx' in globalThis) {
31
+ prngPool = await new Promise(r => {
32
+ wx.getRandomValues({
33
+ length: DEFAULT_PRNG_POOL_SIZE,
34
+ success(res) {
35
+ r(new Uint8Array(res.randomValues));
36
+ }
37
+ });
38
+ });
39
+ } else {
40
+ // check if node, use webcrypto if available
41
+ try {
42
+ const crypto = await import(/* webpackIgnore: true */ 'crypto');
43
+ const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
44
+ crypto.webcrypto.getRandomValues(array);
45
+ prngPool = array;
46
+ } catch (error) {
47
+ throw new Error('no available csprng, abort.');
255
48
  }
256
-
257
- return Q
258
49
  }
259
50
  }
260
51
 
261
- /**
262
- * 椭圆曲线 y^2 = x^3 + ax + b
263
- */
264
- export class ECCurveFp {
265
- infinity: ECPointFp
266
- a: ECFieldElementFp
267
- b: ECFieldElementFp
268
- constructor(public q: BigInteger, a: BigInteger, b: BigInteger) {
269
- this.q = q
270
- this.a = this.fromBigInteger(a)
271
- this.b = this.fromBigInteger(b)
272
- this.infinity = new ECPointFp(this, null, null) // 无穷远点
273
- }
274
-
275
- /**
276
- * 判断两个椭圆曲线是否相等
277
- */
278
- equals(other: ECCurveFp) {
279
- if (other === this) return true
280
- return (this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b))
281
- }
52
+ FillPRNGPoolIfNeeded()
282
53
 
283
- /**
284
- * 生成椭圆曲线域元素
285
- */
286
- fromBigInteger(x: BigInteger) {
287
- return new ECFieldElementFp(this.q, x)
54
+ function consumePool(length: number): Uint8Array {
55
+ if (prngPool.length > length) {
56
+ const prng = prngPool.slice(0, length)
57
+ prngPool = prngPool.slice(length)
58
+ FillPRNGPoolIfNeeded()
59
+ return prng
60
+ } else {
61
+ throw new Error('random number pool is insufficient, prevent getting too long random values or too often.')
288
62
  }
63
+ }
289
64
 
290
- /**
291
- * 解析 16 进制串为椭圆曲线点
292
- */
293
- decodePointHex(s: string) {
294
- switch (parseInt(s.substring(0, 2), 16)) {
295
- // 第一个字节
296
- case 0:
297
- return this.infinity
298
- case 2:
299
- case 3:
300
- // 压缩
301
- const x = this.fromBigInteger(new BigInteger(s.substring(2), 16))
302
- // 对 p ≡ 3 (mod4),即存在正整数 u,使得 p = 4u + 3
303
- // 计算 y = (√ (x^3 + ax + b) % p)^(u + 1) modp
304
- let y = this.fromBigInteger(x.multiply(x.square()).add(
305
- x.multiply(this.a)
306
- ).add(this.b).toBigInteger()
307
- .modPow(
308
- this.q.divide(new BigInteger('4')).add(BigInteger.ONE), this.q
309
- ))
310
- // 算出结果 2 进制最后 1 位不等于第 1 个字节减 2 则取反
311
- if (!y.toBigInteger().mod(TWO).equals(new BigInteger(s.substring(0, 2), 16).subtract(TWO))) {
312
- y = y.negate()
313
- }
314
- return new ECPointFp(this, x, y)
315
- case 4:
316
- case 6:
317
- case 7:
318
- const len = (s.length - 2) / 2
319
- const xHex = s.substring(2, 2 + len)
320
- const yHex = s.substring(len + 2, len + 2 + len)
321
-
322
- return new ECPointFp(this, this.fromBigInteger(new BigInteger(xHex, 16)), this.fromBigInteger(new BigInteger(yHex, 16)))
323
- default:
324
- // 不支持
325
- return null
326
- }
65
+ export function randomBytes(length = 0): Uint8Array {
66
+ const array = new Uint8Array(length);
67
+ if ('crypto' in globalThis) {
68
+ return globalThis.crypto.getRandomValues(array);
69
+ } else {
70
+ return consumePool(length)
327
71
  }
328
72
  }
329
73
 
330
- export const ec = {
331
- ECPointFp,
332
- ECCurveFp,
74
+ export function createHash() {
75
+ const hashC = (msg: Uint8Array | string): Uint8Array => sm3(typeof msg === 'string' ? utf8ToArray(msg) : msg)
76
+ hashC.outputLen = 256;
77
+ hashC.blockLen = 512;
78
+ hashC.create = () => sm3(Uint8Array.from([]));
79
+ return hashC;
333
80
  }
81
+
82
+ export const sm2Fp = Field(BigInt('115792089210356248756420345214020892766250353991924191454421193933289684991999'))
83
+ export const sm2Curve = weierstrass({
84
+ // sm2: short weierstrass.
85
+ a: BigInt('115792089210356248756420345214020892766250353991924191454421193933289684991996'),
86
+ b: BigInt('18505919022281880113072981827955639221458448578012075254857346196103069175443'),
87
+ Fp: sm2Fp,
88
+ h: ONE,
89
+ n: BigInt('115792089210356248756420345214020892766061623724957744567843809356293439045923'),
90
+ Gx: BigInt('22963146547237050559479531362550074578802567295341616970375194840604139615431'),
91
+ Gy: BigInt('85132369209828568825618990617112496413088388631904505083283536607588877201568'),
92
+ hash: createHash(),
93
+ hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(concatArray(...msgs), key),
94
+ randomBytes,
95
+ });