sm-crypto-v2 1.2.2 → 1.3.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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [1.3.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.2.2...v1.3.0) (2023-06-07)
6
+
7
+
8
+ ### Features
9
+
10
+ * **sm2:** add benchmark and optimize rng pooling ([b162377](https://github.com/Cubelrti/sm-crypto-v2/commit/b1623774cc4374deea61499f13790c5e8b17041a))
11
+
5
12
  ### [1.2.2](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.2.1...v1.2.2) (2023-06-07)
6
13
 
7
14
 
package/README.md CHANGED
@@ -37,10 +37,12 @@ privateKey = keypair.privateKey // 私钥
37
37
  const compressedPublicKey = sm2.compressPublicKeyHex(publicKey) // compressedPublicKey 和 publicKey 等价
38
38
  sm2.comparePublicKeyHex(publicKey, compressedPublicKey) // 判断公钥是否等价
39
39
 
40
- // 自定义随机数,参数会直接透传给 jsbn 库的 BigInteger 构造器
40
+ // 自定义随机数,参数会直接透传给 BigInt 构造器
41
41
  // 注意:开发者使用自定义随机数,需要自行确保传入的随机数符合密码学安全
42
42
  let keypair2 = sm2.generateKeyPairHex('123123123123123')
43
- let keypair3 = sm2.generateKeyPairHex(256, SecureRandom)
43
+
44
+ // 初始化随机数池,在某些场景下可能会用到
45
+ await sm2.initRNGPool()
44
46
 
45
47
  let verifyResult = sm2.verifyPublicKey(publicKey) // 验证公钥
46
48
  verifyResult = sm2.verifyPublicKey(compressedPublicKey) // 验证公钥
@@ -168,6 +170,30 @@ let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba9876543
168
170
  * java 实现(感谢 @antherd 提供):[https://github.com/antherd/sm-crypto](https://github.com/antherd/sm-crypto)
169
171
  * dart 实现(感谢 @luckykellan 提供):[https://github.com/luckykellan/dart_sm](https://github.com/luckykellan/dart_sm)
170
172
 
173
+ ## 性能
174
+
175
+ CPU: Apple M1 Pro
176
+
177
+ ```
178
+ ❯ npm run bench
179
+
180
+ > benchmark@0.1.0 bench
181
+ > node index.js
182
+
183
+ Benchmarking
184
+
185
+ === sm-crypto ===
186
+ sm2 generateKeyPair x 134 ops/sec @ 7ms/op ± 4.12% (min: 6ms, max: 21ms)
187
+ sm2 encrypt x 71 ops/sec @ 14ms/op
188
+ sm2 sign x 139 ops/sec @ 7ms/op
189
+ sm2 verify x 70 ops/sec @ 14ms/op
190
+ === sm-crypto-v2 ===
191
+ sm2 generateKeyPair x 2,835 ops/sec @ 352μs/op ± 6.34% (min: 286μs, max: 1ms)
192
+ sm2 encrypt x 253 ops/sec @ 3ms/op ± 2.11% (min: 3ms, max: 24ms)
193
+ sm2 sign x 3,186 ops/sec @ 313μs/op ± 1.26% (min: 277μs, max: 854μs)
194
+ sm2 verify x 258 ops/sec @ 3ms/op
195
+ ```
196
+
171
197
  ## 协议
172
198
 
173
199
  MIT
@@ -0,0 +1,29 @@
1
+ import { run, mark, utils } from 'micro-bmark';
2
+ import * as sm from 'sm-crypto'
3
+ import * as smV2 from 'sm-crypto-v2'
4
+
5
+ const msg = 'Hello world~!'
6
+
7
+ const keypair = smV2.sm2.generateKeyPairHex('12345678901234567890')
8
+
9
+ run(async () => {
10
+ await smV2.sm2.initRNGPool()
11
+ const sig = smV2.sm2.doSignature(msg, keypair.privateKey, { publicKey: keypair.publicKey})
12
+
13
+ const RAM = false
14
+ console.log();
15
+ if (RAM) utils.logMem();
16
+ console.log('=== sm-crypto ===')
17
+ await mark('sm2 generateKeyPair', 100, () => sm.sm2.generateKeyPairHex())
18
+ await mark('sm2 encrypt', 500, () => sm.sm2.doEncrypt(msg, keypair.publicKey));
19
+ await mark('sm2 sign', 500, () => sm.sm2.doSignature(msg, keypair.privateKey, { publicKey: keypair.publicKey}));
20
+ await mark('sm2 verify', 500, () => sm.sm2.doVerifySignature(msg, sig, keypair.publicKey));
21
+ if (RAM) utils.logMem();
22
+ if (RAM) utils.logMem();
23
+ console.log('=== sm-crypto-v2 ===')
24
+ await mark('sm2 generateKeyPair', 100, () => smV2.sm2.generateKeyPairHex())
25
+ await mark('sm2 encrypt', 500, () => smV2.sm2.doEncrypt(msg, keypair.publicKey));
26
+ await mark('sm2 sign', 500, () => smV2.sm2.doSignature(msg, keypair.privateKey, { publicKey: keypair.publicKey}));
27
+ await mark('sm2 verify', 500, () => smV2.sm2.doVerifySignature(msg, sig, keypair.publicKey));
28
+ if (RAM) utils.logMem();
29
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "benchmark",
3
+ "private": true,
4
+ "version": "0.1.0",
5
+ "description": "benchmarks",
6
+ "main": "index.js",
7
+ "type": "module",
8
+ "scripts": {
9
+ "bench": "node index.js"
10
+ },
11
+ "keywords": [],
12
+ "author": "",
13
+ "license": "MIT",
14
+ "dependencies": {
15
+ "micro-bmark": "^0.3.1",
16
+ "sm-crypto": "^0.3.12",
17
+ "sm-crypto-v2": "^1.2.2"
18
+ }
19
+ }
@@ -0,0 +1,28 @@
1
+ lockfileVersion: '6.0'
2
+
3
+ dependencies:
4
+ micro-bmark:
5
+ specifier: ^0.3.1
6
+ version: 0.3.1
7
+ sm-crypto:
8
+ specifier: ^0.3.12
9
+ version: 0.3.12
10
+ sm-crypto-v2:
11
+ specifier: ^1.2.2
12
+ version: link:..
13
+
14
+ packages:
15
+
16
+ /jsbn@1.1.0:
17
+ resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
18
+ dev: false
19
+
20
+ /micro-bmark@0.3.1:
21
+ resolution: {integrity: sha512-bNaKObD4yPAAPrpEqp5jO6LJ2sEFgLoFSmRjEY809mJ62+2AehI/K3+RlVpN3Oo92RHpgC2RQhj6b1Tb4dmo+w==}
22
+ dev: false
23
+
24
+ /sm-crypto@0.3.12:
25
+ resolution: {integrity: sha512-272PBzB4PYaBdeGa41TH9ZlMGLPVRmS36Gs4FjmHwXIdihQypAbhhFWZTaa/3de69q2KfMme1M5O2W5+spAdrg==}
26
+ dependencies:
27
+ jsbn: 1.1.0
28
+ dev: false
package/dist/index.d.ts CHANGED
@@ -39,6 +39,8 @@ declare function verifyPublicKey(publicKey: string): boolean;
39
39
  declare function comparePublicKeyHex(publicKey1: string, publicKey2: string): boolean;
40
40
  declare function concatArray(...arrays: Uint8Array[]): Uint8Array;
41
41
 
42
+ declare function initRNGPool(): Promise<void>;
43
+
42
44
  /**
43
45
  * 加密
44
46
  */
@@ -100,6 +102,7 @@ declare const index$2_doVerifySignature: typeof doVerifySignature;
100
102
  declare const index$2_getHash: typeof getHash;
101
103
  declare const index$2_getPublicKeyFromPrivateKey: typeof getPublicKeyFromPrivateKey;
102
104
  declare const index$2_getPoint: typeof getPoint;
105
+ declare const index$2_initRNGPool: typeof initRNGPool;
103
106
  declare const index$2_generateKeyPairHex: typeof generateKeyPairHex;
104
107
  declare const index$2_compressPublicKeyHex: typeof compressPublicKeyHex;
105
108
  declare const index$2_utf8ToHex: typeof utf8ToHex;
@@ -120,6 +123,7 @@ declare namespace index$2 {
120
123
  index$2_getHash as getHash,
121
124
  index$2_getPublicKeyFromPrivateKey as getPublicKeyFromPrivateKey,
122
125
  index$2_getPoint as getPoint,
126
+ index$2_initRNGPool as initRNGPool,
123
127
  index$2_generateKeyPairHex as generateKeyPairHex,
124
128
  index$2_compressPublicKeyHex as compressPublicKeyHex,
125
129
  index$2_utf8ToHex as utf8ToHex,
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ __export(sm2_exports, {
49
49
  getPoint: () => getPoint,
50
50
  getPublicKeyFromPrivateKey: () => getPublicKeyFromPrivateKey,
51
51
  hexToArray: () => hexToArray,
52
+ initRNGPool: () => initRNGPool,
52
53
  leftPad: () => leftPad2,
53
54
  utf8ToHex: () => utf8ToHex,
54
55
  verifyPublicKey: () => verifyPublicKey
@@ -359,11 +360,14 @@ function sm32(input, options) {
359
360
  }
360
361
 
361
362
  // src/sm2/ec.ts
362
- var DEFAULT_PRNG_POOL_SIZE = 4096;
363
+ var DEFAULT_PRNG_POOL_SIZE = 16384;
363
364
  var prngPool = new Uint8Array(0);
364
- async function FillPRNGPoolIfNeeded() {
365
- if ("crypto" in globalThis)
365
+ var _syncCrypto;
366
+ async function initRNGPool() {
367
+ if ("crypto" in globalThis) {
368
+ _syncCrypto = globalThis.crypto;
366
369
  return;
370
+ }
367
371
  if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
368
372
  return;
369
373
  if ("wx" in globalThis) {
@@ -381,29 +385,30 @@ async function FillPRNGPoolIfNeeded() {
381
385
  /* webpackIgnore: true */
382
386
  "crypto"
383
387
  );
388
+ _syncCrypto = crypto.webcrypto;
384
389
  const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
385
- crypto.webcrypto.getRandomValues(array);
390
+ _syncCrypto.getRandomValues(array);
386
391
  prngPool = array;
387
392
  } catch (error) {
388
393
  throw new Error("no available csprng, abort.");
389
394
  }
390
395
  }
391
396
  }
392
- FillPRNGPoolIfNeeded();
397
+ initRNGPool();
393
398
  function consumePool(length) {
394
399
  if (prngPool.length > length) {
395
400
  const prng = prngPool.slice(0, length);
396
401
  prngPool = prngPool.slice(length);
397
- FillPRNGPoolIfNeeded();
402
+ initRNGPool();
398
403
  return prng;
399
404
  } else {
400
- throw new Error("random number pool is insufficient, prevent getting too long random values or too often.");
405
+ throw new Error("random number pool is not ready or insufficient, prevent getting too long random values or too often.");
401
406
  }
402
407
  }
403
408
  function randomBytes(length = 0) {
404
409
  const array = new Uint8Array(length);
405
- if ("crypto" in globalThis) {
406
- return globalThis.crypto.getRandomValues(array);
410
+ if (_syncCrypto) {
411
+ return _syncCrypto.getRandomValues(array);
407
412
  } else {
408
413
  const result = consumePool(length);
409
414
  return result;
package/dist/index.mjs CHANGED
@@ -21,6 +21,7 @@ __export(sm2_exports, {
21
21
  getPoint: () => getPoint,
22
22
  getPublicKeyFromPrivateKey: () => getPublicKeyFromPrivateKey,
23
23
  hexToArray: () => hexToArray,
24
+ initRNGPool: () => initRNGPool,
24
25
  leftPad: () => leftPad2,
25
26
  utf8ToHex: () => utf8ToHex,
26
27
  verifyPublicKey: () => verifyPublicKey
@@ -331,11 +332,14 @@ function sm32(input, options) {
331
332
  }
332
333
 
333
334
  // src/sm2/ec.ts
334
- var DEFAULT_PRNG_POOL_SIZE = 4096;
335
+ var DEFAULT_PRNG_POOL_SIZE = 16384;
335
336
  var prngPool = new Uint8Array(0);
336
- async function FillPRNGPoolIfNeeded() {
337
- if ("crypto" in globalThis)
337
+ var _syncCrypto;
338
+ async function initRNGPool() {
339
+ if ("crypto" in globalThis) {
340
+ _syncCrypto = globalThis.crypto;
338
341
  return;
342
+ }
339
343
  if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
340
344
  return;
341
345
  if ("wx" in globalThis) {
@@ -353,29 +357,30 @@ async function FillPRNGPoolIfNeeded() {
353
357
  /* webpackIgnore: true */
354
358
  "crypto"
355
359
  );
360
+ _syncCrypto = crypto.webcrypto;
356
361
  const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
357
- crypto.webcrypto.getRandomValues(array);
362
+ _syncCrypto.getRandomValues(array);
358
363
  prngPool = array;
359
364
  } catch (error) {
360
365
  throw new Error("no available csprng, abort.");
361
366
  }
362
367
  }
363
368
  }
364
- FillPRNGPoolIfNeeded();
369
+ initRNGPool();
365
370
  function consumePool(length) {
366
371
  if (prngPool.length > length) {
367
372
  const prng = prngPool.slice(0, length);
368
373
  prngPool = prngPool.slice(length);
369
- FillPRNGPoolIfNeeded();
374
+ initRNGPool();
370
375
  return prng;
371
376
  } else {
372
- throw new Error("random number pool is insufficient, prevent getting too long random values or too often.");
377
+ throw new Error("random number pool is not ready or insufficient, prevent getting too long random values or too often.");
373
378
  }
374
379
  }
375
380
  function randomBytes(length = 0) {
376
381
  const array = new Uint8Array(length);
377
- if ("crypto" in globalThis) {
378
- return globalThis.crypto.getRandomValues(array);
382
+ if (_syncCrypto) {
383
+ return _syncCrypto.getRandomValues(array);
379
384
  } else {
380
385
  const result = consumePool(length);
381
386
  return result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sm-crypto-v2",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "sm-crypto-v2",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/src/sm2/ec.ts CHANGED
@@ -19,11 +19,14 @@ declare module wx {
19
19
  }): void;
20
20
  }
21
21
 
22
- const DEFAULT_PRNG_POOL_SIZE = 4096
22
+ const DEFAULT_PRNG_POOL_SIZE = 16384
23
23
  let prngPool = new Uint8Array(0)
24
-
25
- async function FillPRNGPoolIfNeeded() {
26
- if ('crypto' in globalThis) return // no need to use pooling
24
+ let _syncCrypto: typeof import('crypto')['webcrypto']
25
+ export async function initRNGPool() {
26
+ if ('crypto' in globalThis) {
27
+ _syncCrypto = globalThis.crypto
28
+ return // no need to use pooling
29
+ }
27
30
  if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2) return // there is sufficient number
28
31
  // we always populate full pool size
29
32
  // since numbers may be consumed during micro tasks.
@@ -40,8 +43,9 @@ async function FillPRNGPoolIfNeeded() {
40
43
  // check if node, use webcrypto if available
41
44
  try {
42
45
  const crypto = await import(/* webpackIgnore: true */ 'crypto');
46
+ _syncCrypto = crypto.webcrypto
43
47
  const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
44
- crypto.webcrypto.getRandomValues(array);
48
+ _syncCrypto.getRandomValues(array);
45
49
  prngPool = array;
46
50
  } catch (error) {
47
51
  throw new Error('no available csprng, abort.');
@@ -49,24 +53,25 @@ async function FillPRNGPoolIfNeeded() {
49
53
  }
50
54
  }
51
55
 
52
- FillPRNGPoolIfNeeded()
56
+ initRNGPool()
53
57
 
54
58
  function consumePool(length: number): Uint8Array {
55
59
  if (prngPool.length > length) {
56
60
  const prng = prngPool.slice(0, length)
57
61
  prngPool = prngPool.slice(length)
58
- FillPRNGPoolIfNeeded()
62
+ initRNGPool()
59
63
  return prng
60
64
  } else {
61
- throw new Error('random number pool is insufficient, prevent getting too long random values or too often.')
65
+ throw new Error('random number pool is not ready or insufficient, prevent getting too long random values or too often.')
62
66
  }
63
67
  }
64
68
 
65
69
  export function randomBytes(length = 0): Uint8Array {
66
70
  const array = new Uint8Array(length);
67
- if ('crypto' in globalThis) {
68
- return globalThis.crypto.getRandomValues(array);
71
+ if (_syncCrypto) {
72
+ return _syncCrypto.getRandomValues(array);
69
73
  } else {
74
+ // no sync crypto available, use async pool
70
75
  const result = consumePool(length)
71
76
  return result
72
77
  }
package/src/sm2/index.ts CHANGED
@@ -2,12 +2,14 @@
2
2
  import { encodeDer, decodeDer } from './asn1'
3
3
  import { arrayToHex, arrayToUtf8, concatArray, generateKeyPairHex, hexToArray, leftPad, utf8ToHex } from './utils'
4
4
  import { sm3 } from './sm3'
5
- export * from './utils'
6
5
  import * as mod from '@noble/curves/abstract/modular';
7
6
  import * as utils from '@noble/curves/abstract/utils';
8
7
  import { sm2Curve } from './ec';
9
8
  import { ONE, ZERO } from './bn';
10
9
 
10
+ export * from './utils'
11
+ export { initRNGPool } from './ec'
12
+
11
13
  // const { G, curve, n } = generateEcparam()
12
14
  const C1C2C3 = 0
13
15