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 +7 -0
- package/README.md +28 -2
- package/benchmark/index.js +29 -0
- package/benchmark/package.json +19 -0
- package/benchmark/pnpm-lock.yaml +28 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +14 -9
- package/dist/index.mjs +14 -9
- package/package.json +1 -1
- package/src/sm2/ec.ts +15 -10
- package/src/sm2/index.ts +3 -1
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
|
-
// 自定义随机数,参数会直接透传给
|
40
|
+
// 自定义随机数,参数会直接透传给 BigInt 构造器
|
41
41
|
// 注意:开发者使用自定义随机数,需要自行确保传入的随机数符合密码学安全
|
42
42
|
let keypair2 = sm2.generateKeyPairHex('123123123123123')
|
43
|
-
|
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 =
|
363
|
+
var DEFAULT_PRNG_POOL_SIZE = 16384;
|
363
364
|
var prngPool = new Uint8Array(0);
|
364
|
-
|
365
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 (
|
406
|
-
return
|
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 =
|
335
|
+
var DEFAULT_PRNG_POOL_SIZE = 16384;
|
335
336
|
var prngPool = new Uint8Array(0);
|
336
|
-
|
337
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 (
|
378
|
-
return
|
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
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 =
|
22
|
+
const DEFAULT_PRNG_POOL_SIZE = 16384
|
23
23
|
let prngPool = new Uint8Array(0)
|
24
|
-
|
25
|
-
async function
|
26
|
-
if ('crypto' in globalThis)
|
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
|
-
|
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
|
-
|
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
|
-
|
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 (
|
68
|
-
return
|
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
|
|