sm-crypto-v2 1.2.2 → 1.4.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,20 @@
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.4.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.3.0...v1.4.0) (2023-06-09)
6
+
7
+
8
+ ### Features
9
+
10
+ * **sm2:** add experimental key agreement ([cdd00b4](https://github.com/Cubelrti/sm-crypto-v2/commit/cdd00b4e42bb5072e1dcb6e0301b6a2f18f53614))
11
+
12
+ ## [1.3.0](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.2.2...v1.3.0) (2023-06-07)
13
+
14
+
15
+ ### Features
16
+
17
+ * **sm2:** add benchmark and optimize rng pooling ([b162377](https://github.com/Cubelrti/sm-crypto-v2/commit/b1623774cc4374deea61499f13790c5e8b17041a))
18
+
5
19
  ### [1.2.2](https://github.com/Cubelrti/sm-crypto-v2/compare/v1.2.1...v1.2.2) (2023-06-07)
6
20
 
7
21
 
package/README.md CHANGED
@@ -1,19 +1,19 @@
1
1
  # sm-crypto-v2
2
2
 
3
- [![npm version](https://badge.fury.io/js/sm-crypto-v2.svg)](https://badge.fury.io/js/sm-crypto-v2)
3
+ [![npm version](https://badge.fury.io/js/sm-crypto-v2.svg)](https://www.npmjs.com/package/sm-crypto-v2)
4
4
  [![status](https://img.shields.io/github/actions/workflow/status/cubelrti/sm-crypto-v2/test.yml?branch=master)](https://github.com/cubelrti/sm-crypto-v2/actions)
5
5
  [![cov](https://cubelrti.github.io/sm-crypto-v2/badges/coverage.svg)](https://github.com/cubelrti/sm-crypto-v2/actions)
6
6
 
7
-
8
7
  国密算法 sm2、sm3 和 sm4 的 TypeScript 实现。参数支持 TypedArray,导出 esm/cjs。
9
8
 
10
9
  ## 特性
11
10
 
12
- - SM2 底层改用 `noble-curves`,性能提升接近4倍,[noble-curves 文档](https://github.com/paulmillr/noble-curves)
13
- - 完整的类型支持
14
- - 移除原有 `jsbn` 依赖,改用原生 BigInt 支持
15
- - 通过所有之前的单元测试,包括 SM2、SM3 和 SM4
16
- - 自动使用最优的安全随机数实现,不使用 `random` 和 `Date.now` 模拟
11
+ - 基于 [`noble-curves` Abstract API](https://github.com/paulmillr/noble-curves#abstract-api) 重构 SM2,性能提升近4倍。详见 [noble-curves 文档](https://paulmillr.com/posts/noble-secp256k1-fast-ecc/)
12
+ - 📘 使用 TypeScript 实现,提供全面的类型支持
13
+ - 🔄 移除原有 `jsbn` 依赖,改用原生 BigInt
14
+ - ✔️ 通过全部历史单元测试,包括 SM2、SM3 和 SM4
15
+ - 🎲 自动选择最优的安全随机数实现,避免使用 `Math.random` 和 `Date.now` 进行模拟
16
+ - 📚 同时导出 ES Module 和 CommonJS 两种格式,可按需使用
17
17
 
18
18
  ## 安装
19
19
 
@@ -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) // 验证公钥
@@ -161,6 +163,24 @@ let decryptData = sm4.decrypt(encryptData, key, {padding: 'none', output: 'array
161
163
  let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba98765432100123456789abcdef'}) // 解密,cbc 模式
162
164
  ```
163
165
 
166
+ ### 密钥交换(实验性)
167
+
168
+ ```js
169
+ import { sm2 } from 'sm-crypto-v2'
170
+
171
+ const keyPairA = sm2.generateKeyPairHex() // A 的秘钥对
172
+ const keyPairB = sm2.generateKeyPairHex() // B 的秘钥对
173
+ const ephemeralKeypairA = sm2.generateKeyPairHex() // A 的临时秘钥对
174
+ const ephemeralKeypairB = sm2.generateKeyPairHex() // B 的临时秘钥对
175
+
176
+ // A 所需参数:A 的秘钥对,A 的临时秘钥对,B 的公钥,B 的临时秘钥公钥,AB 的身份ID,长度
177
+ const sharedKeyFromA = sm2.calculateSharedKey(keyPairA, ephemeralKeypairA, keyPairB.publicKey, ephemeralKeypairB.publicKey, undefined, undefined, 233)
178
+ // A 所需参数:B 的秘钥对,B 的临时秘钥对,A 的公钥,A 的临时秘钥公钥,AB 的身份ID,长度
179
+ const sharedKeyFromB = sm2.calculateSharedKey(keyPairB, ephemeralKeypairB, keyPairA.publicKey, ephemeralKeypairA.publicKey, undefined, undefined, 233)
180
+
181
+ // expect(sharedKeyFromA).toEqual(sharedKeyFromB) => true
182
+ ```
183
+
164
184
  ## 其他实现
165
185
 
166
186
  * 原 js 版本:[https://github.com/JuneAndGreen/sm-crypto](https://github.com/JuneAndGreen/sm-crypto)
@@ -168,6 +188,30 @@ let decryptData = sm4.decrypt(encryptData, key, {mode: 'cbc', iv: 'fedcba9876543
168
188
  * java 实现(感谢 @antherd 提供):[https://github.com/antherd/sm-crypto](https://github.com/antherd/sm-crypto)
169
189
  * dart 实现(感谢 @luckykellan 提供):[https://github.com/luckykellan/dart_sm](https://github.com/luckykellan/dart_sm)
170
190
 
191
+ ## 性能
192
+
193
+ CPU: Apple M1 Pro
194
+
195
+ ```
196
+ ❯ npm run bench
197
+
198
+ > benchmark@0.1.0 bench
199
+ > node index.js
200
+
201
+ Benchmarking
202
+
203
+ === sm-crypto ===
204
+ sm2 generateKeyPair x 134 ops/sec @ 7ms/op ± 4.12% (min: 6ms, max: 21ms)
205
+ sm2 encrypt x 71 ops/sec @ 14ms/op
206
+ sm2 sign x 139 ops/sec @ 7ms/op
207
+ sm2 verify x 70 ops/sec @ 14ms/op
208
+ === sm-crypto-v2 ===
209
+ sm2 generateKeyPair x 2,835 ops/sec @ 352μs/op ± 6.34% (min: 286μs, max: 1ms)
210
+ sm2 encrypt x 253 ops/sec @ 3ms/op ± 2.11% (min: 3ms, max: 24ms)
211
+ sm2 sign x 3,186 ops/sec @ 313μs/op ± 1.26% (min: 277μs, max: 854μs)
212
+ sm2 verify x 258 ops/sec @ 3ms/op
213
+ ```
214
+
171
215
  ## 协议
172
216
 
173
217
  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
@@ -1,10 +1,11 @@
1
+ interface KeyPair {
2
+ privateKey: string;
3
+ publicKey: string;
4
+ }
1
5
  /**
2
6
  * 生成密钥对:publicKey = privateKey * G
3
7
  */
4
- declare function generateKeyPairHex(str?: string): {
5
- privateKey: string;
6
- publicKey: string;
7
- };
8
+ declare function generateKeyPairHex(str?: string): KeyPair;
8
9
  /**
9
10
  * 生成压缩公钥
10
11
  */
@@ -39,6 +40,10 @@ declare function verifyPublicKey(publicKey: string): boolean;
39
40
  declare function comparePublicKeyHex(publicKey1: string, publicKey2: string): boolean;
40
41
  declare function concatArray(...arrays: Uint8Array[]): Uint8Array;
41
42
 
43
+ declare function initRNGPool(): Promise<void>;
44
+
45
+ declare function calculateSharedKey(keypairA: KeyPair, ephemeralKeypairA: KeyPair, publicKeyB: string, ephemeralPublicKeyB: string, idA: string | undefined, idB: string | undefined, sharedKeyLength: number): Uint8Array;
46
+
42
47
  /**
43
48
  * 加密
44
49
  */
@@ -100,6 +105,9 @@ declare const index$2_doVerifySignature: typeof doVerifySignature;
100
105
  declare const index$2_getHash: typeof getHash;
101
106
  declare const index$2_getPublicKeyFromPrivateKey: typeof getPublicKeyFromPrivateKey;
102
107
  declare const index$2_getPoint: typeof getPoint;
108
+ declare const index$2_initRNGPool: typeof initRNGPool;
109
+ declare const index$2_calculateSharedKey: typeof calculateSharedKey;
110
+ type index$2_KeyPair = KeyPair;
103
111
  declare const index$2_generateKeyPairHex: typeof generateKeyPairHex;
104
112
  declare const index$2_compressPublicKeyHex: typeof compressPublicKeyHex;
105
113
  declare const index$2_utf8ToHex: typeof utf8ToHex;
@@ -120,6 +128,9 @@ declare namespace index$2 {
120
128
  index$2_getHash as getHash,
121
129
  index$2_getPublicKeyFromPrivateKey as getPublicKeyFromPrivateKey,
122
130
  index$2_getPoint as getPoint,
131
+ index$2_initRNGPool as initRNGPool,
132
+ index$2_calculateSharedKey as calculateSharedKey,
133
+ index$2_KeyPair as KeyPair,
123
134
  index$2_generateKeyPairHex as generateKeyPairHex,
124
135
  index$2_compressPublicKeyHex as compressPublicKeyHex,
125
136
  index$2_utf8ToHex as utf8ToHex,
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ var sm2_exports = {};
37
37
  __export(sm2_exports, {
38
38
  arrayToHex: () => arrayToHex,
39
39
  arrayToUtf8: () => arrayToUtf8,
40
+ calculateSharedKey: () => calculateSharedKey,
40
41
  comparePublicKeyHex: () => comparePublicKeyHex,
41
42
  compressPublicKeyHex: () => compressPublicKeyHex,
42
43
  concatArray: () => concatArray,
@@ -49,6 +50,7 @@ __export(sm2_exports, {
49
50
  getPoint: () => getPoint,
50
51
  getPublicKeyFromPrivateKey: () => getPublicKeyFromPrivateKey,
51
52
  hexToArray: () => hexToArray,
53
+ initRNGPool: () => initRNGPool,
52
54
  leftPad: () => leftPad2,
53
55
  utf8ToHex: () => utf8ToHex,
54
56
  verifyPublicKey: () => verifyPublicKey
@@ -359,11 +361,14 @@ function sm32(input, options) {
359
361
  }
360
362
 
361
363
  // src/sm2/ec.ts
362
- var DEFAULT_PRNG_POOL_SIZE = 4096;
364
+ var DEFAULT_PRNG_POOL_SIZE = 16384;
363
365
  var prngPool = new Uint8Array(0);
364
- async function FillPRNGPoolIfNeeded() {
365
- if ("crypto" in globalThis)
366
+ var _syncCrypto;
367
+ async function initRNGPool() {
368
+ if ("crypto" in globalThis) {
369
+ _syncCrypto = globalThis.crypto;
366
370
  return;
371
+ }
367
372
  if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
368
373
  return;
369
374
  if ("wx" in globalThis) {
@@ -381,29 +386,30 @@ async function FillPRNGPoolIfNeeded() {
381
386
  /* webpackIgnore: true */
382
387
  "crypto"
383
388
  );
389
+ _syncCrypto = crypto.webcrypto;
384
390
  const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
385
- crypto.webcrypto.getRandomValues(array);
391
+ _syncCrypto.getRandomValues(array);
386
392
  prngPool = array;
387
393
  } catch (error) {
388
394
  throw new Error("no available csprng, abort.");
389
395
  }
390
396
  }
391
397
  }
392
- FillPRNGPoolIfNeeded();
398
+ initRNGPool();
393
399
  function consumePool(length) {
394
400
  if (prngPool.length > length) {
395
401
  const prng = prngPool.slice(0, length);
396
402
  prngPool = prngPool.slice(length);
397
- FillPRNGPoolIfNeeded();
403
+ initRNGPool();
398
404
  return prng;
399
405
  } else {
400
- throw new Error("random number pool is insufficient, prevent getting too long random values or too often.");
406
+ throw new Error("random number pool is not ready or insufficient, prevent getting too long random values or too often.");
401
407
  }
402
408
  }
403
409
  function randomBytes(length = 0) {
404
410
  const array = new Uint8Array(length);
405
- if ("crypto" in globalThis) {
406
- return globalThis.crypto.getRandomValues(array);
411
+ if (_syncCrypto) {
412
+ return _syncCrypto.getRandomValues(array);
407
413
  } else {
408
414
  const result = consumePool(length);
409
415
  return result;
@@ -539,19 +545,65 @@ function concatArray(...arrays) {
539
545
 
540
546
  // src/sm2/index.ts
541
547
  var mod2 = __toESM(require("@noble/curves/abstract/modular"));
548
+ var utils4 = __toESM(require("@noble/curves/abstract/utils"));
549
+
550
+ // src/sm2/kx.ts
542
551
  var utils3 = __toESM(require("@noble/curves/abstract/utils"));
552
+ var import_modular3 = require("@noble/curves/abstract/modular");
553
+ var field = (0, import_modular3.Field)(BigInt(sm2Curve.CURVE.n));
554
+ var wPow2 = utils3.hexToNumber("80000000000000000000000000000000");
555
+ var wPow2Sub1 = utils3.hexToNumber("7fffffffffffffffffffffffffffffff");
556
+ function hkdf(z, keylen) {
557
+ let t = new Uint8Array();
558
+ let msg = new Uint8Array(keylen);
559
+ let ct = 1;
560
+ let offset = 0;
561
+ const nextT = () => {
562
+ t = sm3(Uint8Array.from([...z, ct >> 24 & 255, ct >> 16 & 255, ct >> 8 & 255, ct & 255]));
563
+ ct++;
564
+ offset = 0;
565
+ };
566
+ nextT();
567
+ for (let i = 0, len = msg.length; i < len; i++) {
568
+ if (offset === t.length)
569
+ nextT();
570
+ msg[i] = t[offset++] & 255;
571
+ }
572
+ return msg;
573
+ }
574
+ function calculateSharedKey(keypairA, ephemeralKeypairA, publicKeyB, ephemeralPublicKeyB, idA = "1234567812345678", idB = "1234567812345678", sharedKeyLength) {
575
+ const RA = sm2Curve.ProjectivePoint.fromHex(ephemeralKeypairA.publicKey);
576
+ const RB = sm2Curve.ProjectivePoint.fromHex(ephemeralPublicKeyB);
577
+ const PB = sm2Curve.ProjectivePoint.fromHex(publicKeyB);
578
+ const ZA = hexToArray(idA);
579
+ const ZB = hexToArray(idB);
580
+ const rA = utils3.hexToNumber(ephemeralKeypairA.privateKey);
581
+ const dA = utils3.hexToNumber(keypairA.privateKey);
582
+ const x1 = RA.x;
583
+ const x1_ = field.add(wPow2, x1 & wPow2Sub1);
584
+ const tA = field.add(dA, field.mul(x1_, rA));
585
+ const x2 = RB.x;
586
+ const x2_ = field.add(wPow2, x2 & wPow2Sub1);
587
+ const U = RB.multiply(x2_).add(PB).multiply(tA);
588
+ const xU = hexToArray(leftPad2(utils3.numberToHexUnpadded(U.x), 64));
589
+ const yU = hexToArray(leftPad2(utils3.numberToHexUnpadded(U.y), 64));
590
+ const KA = hkdf(concatArray(xU, yU, ZA, ZB), sharedKeyLength);
591
+ return KA;
592
+ }
593
+
594
+ // src/sm2/index.ts
543
595
  var C1C2C3 = 0;
544
596
  function doEncrypt(msg, publicKey, cipherMode = 1) {
545
597
  const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
546
598
  const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
547
599
  const keypair = generateKeyPairHex();
548
- const k = utils3.hexToNumber(keypair.privateKey);
600
+ const k = utils4.hexToNumber(keypair.privateKey);
549
601
  let c1 = keypair.publicKey;
550
602
  if (c1.length > 128)
551
603
  c1 = c1.substring(c1.length - 128);
552
604
  const p = publicKeyPoint.multiply(k);
553
- const x2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.x), 64));
554
- const y2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.y), 64));
605
+ const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
606
+ const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
555
607
  const c3 = arrayToHex(Array.from(sm3(concatArray(x2, msgArr, y2))));
556
608
  let ct = 1;
557
609
  let offset = 0;
@@ -574,7 +626,7 @@ function doEncrypt(msg, publicKey, cipherMode = 1) {
574
626
  function doDecrypt(encryptData, privateKey, cipherMode = 1, {
575
627
  output = "string"
576
628
  } = {}) {
577
- const privateKeyInteger = utils3.hexToNumber(privateKey);
629
+ const privateKeyInteger = utils4.hexToNumber(privateKey);
578
630
  let c3 = encryptData.substring(128, 128 + 64);
579
631
  let c2 = encryptData.substring(128 + 64);
580
632
  if (cipherMode === C1C2C3) {
@@ -584,8 +636,8 @@ function doDecrypt(encryptData, privateKey, cipherMode = 1, {
584
636
  const msg = hexToArray(c2);
585
637
  const c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
586
638
  const p = c1.multiply(privateKeyInteger);
587
- const x2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.x), 64));
588
- const y2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.y), 64));
639
+ const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
640
+ const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
589
641
  let ct = 1;
590
642
  let offset = 0;
591
643
  let t = new Uint8Array();
@@ -621,8 +673,8 @@ function doSignature(msg, privateKey, options = {}) {
621
673
  publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey);
622
674
  hashHex = getHash(hashHex, publicKey, userId);
623
675
  }
624
- const dA = utils3.hexToNumber(privateKey);
625
- const e = utils3.hexToNumber(hashHex);
676
+ const dA = utils4.hexToNumber(privateKey);
677
+ const e = utils4.hexToNumber(hashHex);
626
678
  let k = null;
627
679
  let r = null;
628
680
  let s = null;
@@ -641,7 +693,7 @@ function doSignature(msg, privateKey, options = {}) {
641
693
  } while (s === ZERO);
642
694
  if (der)
643
695
  return encodeDer(r, s);
644
- return leftPad2(utils3.numberToHexUnpadded(r), 64) + leftPad2(utils3.numberToHexUnpadded(s), 64);
696
+ return leftPad2(utils4.numberToHexUnpadded(r), 64) + leftPad2(utils4.numberToHexUnpadded(s), 64);
645
697
  }
646
698
  function doVerifySignature(msg, signHex, publicKey, options = {}) {
647
699
  let hashHex;
@@ -662,11 +714,11 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
662
714
  r = decodeDerObj.r;
663
715
  s = decodeDerObj.s;
664
716
  } else {
665
- r = utils3.hexToNumber(signHex.substring(0, 64));
666
- s = utils3.hexToNumber(signHex.substring(64));
717
+ r = utils4.hexToNumber(signHex.substring(0, 64));
718
+ s = utils4.hexToNumber(signHex.substring(64));
667
719
  }
668
720
  const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
669
- const e = utils3.hexToNumber(hashHex);
721
+ const e = utils4.hexToNumber(hashHex);
670
722
  const t = mod2.mod(r + s, sm2Curve.CURVE.n);
671
723
  if (t === ZERO)
672
724
  return false;
@@ -676,10 +728,10 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
676
728
  }
677
729
  function getHash(hashHex, publicKey, userId = "1234567812345678") {
678
730
  userId = utf8ToHex(userId);
679
- const a = leftPad2(utils3.numberToHexUnpadded(sm2Curve.CURVE.a), 64);
680
- const b = leftPad2(utils3.numberToHexUnpadded(sm2Curve.CURVE.b), 64);
681
- const gx = leftPad2(utils3.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64);
682
- const gy = leftPad2(utils3.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64);
731
+ const a = leftPad2(utils4.numberToHexUnpadded(sm2Curve.CURVE.a), 64);
732
+ const b = leftPad2(utils4.numberToHexUnpadded(sm2Curve.CURVE.b), 64);
733
+ const gx = leftPad2(utils4.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64);
734
+ const gy = leftPad2(utils4.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64);
683
735
  let px;
684
736
  let py;
685
737
  if (publicKey.length === 128) {
@@ -687,8 +739,8 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
687
739
  py = publicKey.substring(64, 128);
688
740
  } else {
689
741
  const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
690
- px = leftPad2(utils3.numberToHexUnpadded(point.x), 64);
691
- py = leftPad2(utils3.numberToHexUnpadded(point.y), 64);
742
+ px = leftPad2(utils4.numberToHexUnpadded(point.x), 64);
743
+ py = leftPad2(utils4.numberToHexUnpadded(point.y), 64);
692
744
  }
693
745
  const data = hexToArray(userId + a + b + gx + gy + px + py);
694
746
  const entl = userId.length * 4;
@@ -697,13 +749,13 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
697
749
  }
698
750
  function getPublicKeyFromPrivateKey(privateKey) {
699
751
  const pubKey = sm2Curve.getPublicKey(privateKey, false);
700
- const pubPad = leftPad2(utils3.bytesToHex(pubKey), 64);
752
+ const pubPad = leftPad2(utils4.bytesToHex(pubKey), 64);
701
753
  return pubPad;
702
754
  }
703
755
  function getPoint() {
704
756
  const keypair = generateKeyPairHex();
705
757
  const PA = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey);
706
- const k = utils3.hexToNumber(keypair.privateKey);
758
+ const k = utils4.hexToNumber(keypair.privateKey);
707
759
  return {
708
760
  ...keypair,
709
761
  k,
package/dist/index.mjs CHANGED
@@ -9,6 +9,7 @@ var sm2_exports = {};
9
9
  __export(sm2_exports, {
10
10
  arrayToHex: () => arrayToHex,
11
11
  arrayToUtf8: () => arrayToUtf8,
12
+ calculateSharedKey: () => calculateSharedKey,
12
13
  comparePublicKeyHex: () => comparePublicKeyHex,
13
14
  compressPublicKeyHex: () => compressPublicKeyHex,
14
15
  concatArray: () => concatArray,
@@ -21,6 +22,7 @@ __export(sm2_exports, {
21
22
  getPoint: () => getPoint,
22
23
  getPublicKeyFromPrivateKey: () => getPublicKeyFromPrivateKey,
23
24
  hexToArray: () => hexToArray,
25
+ initRNGPool: () => initRNGPool,
24
26
  leftPad: () => leftPad2,
25
27
  utf8ToHex: () => utf8ToHex,
26
28
  verifyPublicKey: () => verifyPublicKey
@@ -331,11 +333,14 @@ function sm32(input, options) {
331
333
  }
332
334
 
333
335
  // src/sm2/ec.ts
334
- var DEFAULT_PRNG_POOL_SIZE = 4096;
336
+ var DEFAULT_PRNG_POOL_SIZE = 16384;
335
337
  var prngPool = new Uint8Array(0);
336
- async function FillPRNGPoolIfNeeded() {
337
- if ("crypto" in globalThis)
338
+ var _syncCrypto;
339
+ async function initRNGPool() {
340
+ if ("crypto" in globalThis) {
341
+ _syncCrypto = globalThis.crypto;
338
342
  return;
343
+ }
339
344
  if (prngPool.length > DEFAULT_PRNG_POOL_SIZE / 2)
340
345
  return;
341
346
  if ("wx" in globalThis) {
@@ -353,29 +358,30 @@ async function FillPRNGPoolIfNeeded() {
353
358
  /* webpackIgnore: true */
354
359
  "crypto"
355
360
  );
361
+ _syncCrypto = crypto.webcrypto;
356
362
  const array = new Uint8Array(DEFAULT_PRNG_POOL_SIZE);
357
- crypto.webcrypto.getRandomValues(array);
363
+ _syncCrypto.getRandomValues(array);
358
364
  prngPool = array;
359
365
  } catch (error) {
360
366
  throw new Error("no available csprng, abort.");
361
367
  }
362
368
  }
363
369
  }
364
- FillPRNGPoolIfNeeded();
370
+ initRNGPool();
365
371
  function consumePool(length) {
366
372
  if (prngPool.length > length) {
367
373
  const prng = prngPool.slice(0, length);
368
374
  prngPool = prngPool.slice(length);
369
- FillPRNGPoolIfNeeded();
375
+ initRNGPool();
370
376
  return prng;
371
377
  } else {
372
- throw new Error("random number pool is insufficient, prevent getting too long random values or too often.");
378
+ throw new Error("random number pool is not ready or insufficient, prevent getting too long random values or too often.");
373
379
  }
374
380
  }
375
381
  function randomBytes(length = 0) {
376
382
  const array = new Uint8Array(length);
377
- if ("crypto" in globalThis) {
378
- return globalThis.crypto.getRandomValues(array);
383
+ if (_syncCrypto) {
384
+ return _syncCrypto.getRandomValues(array);
379
385
  } else {
380
386
  const result = consumePool(length);
381
387
  return result;
@@ -511,19 +517,65 @@ function concatArray(...arrays) {
511
517
 
512
518
  // src/sm2/index.ts
513
519
  import * as mod2 from "@noble/curves/abstract/modular";
520
+ import * as utils4 from "@noble/curves/abstract/utils";
521
+
522
+ // src/sm2/kx.ts
514
523
  import * as utils3 from "@noble/curves/abstract/utils";
524
+ import { Field as Field2 } from "@noble/curves/abstract/modular";
525
+ var field = Field2(BigInt(sm2Curve.CURVE.n));
526
+ var wPow2 = utils3.hexToNumber("80000000000000000000000000000000");
527
+ var wPow2Sub1 = utils3.hexToNumber("7fffffffffffffffffffffffffffffff");
528
+ function hkdf(z, keylen) {
529
+ let t = new Uint8Array();
530
+ let msg = new Uint8Array(keylen);
531
+ let ct = 1;
532
+ let offset = 0;
533
+ const nextT = () => {
534
+ t = sm3(Uint8Array.from([...z, ct >> 24 & 255, ct >> 16 & 255, ct >> 8 & 255, ct & 255]));
535
+ ct++;
536
+ offset = 0;
537
+ };
538
+ nextT();
539
+ for (let i = 0, len = msg.length; i < len; i++) {
540
+ if (offset === t.length)
541
+ nextT();
542
+ msg[i] = t[offset++] & 255;
543
+ }
544
+ return msg;
545
+ }
546
+ function calculateSharedKey(keypairA, ephemeralKeypairA, publicKeyB, ephemeralPublicKeyB, idA = "1234567812345678", idB = "1234567812345678", sharedKeyLength) {
547
+ const RA = sm2Curve.ProjectivePoint.fromHex(ephemeralKeypairA.publicKey);
548
+ const RB = sm2Curve.ProjectivePoint.fromHex(ephemeralPublicKeyB);
549
+ const PB = sm2Curve.ProjectivePoint.fromHex(publicKeyB);
550
+ const ZA = hexToArray(idA);
551
+ const ZB = hexToArray(idB);
552
+ const rA = utils3.hexToNumber(ephemeralKeypairA.privateKey);
553
+ const dA = utils3.hexToNumber(keypairA.privateKey);
554
+ const x1 = RA.x;
555
+ const x1_ = field.add(wPow2, x1 & wPow2Sub1);
556
+ const tA = field.add(dA, field.mul(x1_, rA));
557
+ const x2 = RB.x;
558
+ const x2_ = field.add(wPow2, x2 & wPow2Sub1);
559
+ const U = RB.multiply(x2_).add(PB).multiply(tA);
560
+ const xU = hexToArray(leftPad2(utils3.numberToHexUnpadded(U.x), 64));
561
+ const yU = hexToArray(leftPad2(utils3.numberToHexUnpadded(U.y), 64));
562
+ const KA = hkdf(concatArray(xU, yU, ZA, ZB), sharedKeyLength);
563
+ return KA;
564
+ }
565
+
566
+ // src/sm2/index.ts
515
567
  var C1C2C3 = 0;
516
568
  function doEncrypt(msg, publicKey, cipherMode = 1) {
517
569
  const msgArr = typeof msg === "string" ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg);
518
570
  const publicKeyPoint = sm2Curve.ProjectivePoint.fromHex(publicKey);
519
571
  const keypair = generateKeyPairHex();
520
- const k = utils3.hexToNumber(keypair.privateKey);
572
+ const k = utils4.hexToNumber(keypair.privateKey);
521
573
  let c1 = keypair.publicKey;
522
574
  if (c1.length > 128)
523
575
  c1 = c1.substring(c1.length - 128);
524
576
  const p = publicKeyPoint.multiply(k);
525
- const x2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.x), 64));
526
- const y2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.y), 64));
577
+ const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
578
+ const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
527
579
  const c3 = arrayToHex(Array.from(sm3(concatArray(x2, msgArr, y2))));
528
580
  let ct = 1;
529
581
  let offset = 0;
@@ -546,7 +598,7 @@ function doEncrypt(msg, publicKey, cipherMode = 1) {
546
598
  function doDecrypt(encryptData, privateKey, cipherMode = 1, {
547
599
  output = "string"
548
600
  } = {}) {
549
- const privateKeyInteger = utils3.hexToNumber(privateKey);
601
+ const privateKeyInteger = utils4.hexToNumber(privateKey);
550
602
  let c3 = encryptData.substring(128, 128 + 64);
551
603
  let c2 = encryptData.substring(128 + 64);
552
604
  if (cipherMode === C1C2C3) {
@@ -556,8 +608,8 @@ function doDecrypt(encryptData, privateKey, cipherMode = 1, {
556
608
  const msg = hexToArray(c2);
557
609
  const c1 = sm2Curve.ProjectivePoint.fromHex("04" + encryptData.substring(0, 128));
558
610
  const p = c1.multiply(privateKeyInteger);
559
- const x2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.x), 64));
560
- const y2 = hexToArray(leftPad2(utils3.numberToHexUnpadded(p.y), 64));
611
+ const x2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.x), 64));
612
+ const y2 = hexToArray(leftPad2(utils4.numberToHexUnpadded(p.y), 64));
561
613
  let ct = 1;
562
614
  let offset = 0;
563
615
  let t = new Uint8Array();
@@ -593,8 +645,8 @@ function doSignature(msg, privateKey, options = {}) {
593
645
  publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey);
594
646
  hashHex = getHash(hashHex, publicKey, userId);
595
647
  }
596
- const dA = utils3.hexToNumber(privateKey);
597
- const e = utils3.hexToNumber(hashHex);
648
+ const dA = utils4.hexToNumber(privateKey);
649
+ const e = utils4.hexToNumber(hashHex);
598
650
  let k = null;
599
651
  let r = null;
600
652
  let s = null;
@@ -613,7 +665,7 @@ function doSignature(msg, privateKey, options = {}) {
613
665
  } while (s === ZERO);
614
666
  if (der)
615
667
  return encodeDer(r, s);
616
- return leftPad2(utils3.numberToHexUnpadded(r), 64) + leftPad2(utils3.numberToHexUnpadded(s), 64);
668
+ return leftPad2(utils4.numberToHexUnpadded(r), 64) + leftPad2(utils4.numberToHexUnpadded(s), 64);
617
669
  }
618
670
  function doVerifySignature(msg, signHex, publicKey, options = {}) {
619
671
  let hashHex;
@@ -634,11 +686,11 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
634
686
  r = decodeDerObj.r;
635
687
  s = decodeDerObj.s;
636
688
  } else {
637
- r = utils3.hexToNumber(signHex.substring(0, 64));
638
- s = utils3.hexToNumber(signHex.substring(64));
689
+ r = utils4.hexToNumber(signHex.substring(0, 64));
690
+ s = utils4.hexToNumber(signHex.substring(64));
639
691
  }
640
692
  const PA = sm2Curve.ProjectivePoint.fromHex(publicKey);
641
- const e = utils3.hexToNumber(hashHex);
693
+ const e = utils4.hexToNumber(hashHex);
642
694
  const t = mod2.mod(r + s, sm2Curve.CURVE.n);
643
695
  if (t === ZERO)
644
696
  return false;
@@ -648,10 +700,10 @@ function doVerifySignature(msg, signHex, publicKey, options = {}) {
648
700
  }
649
701
  function getHash(hashHex, publicKey, userId = "1234567812345678") {
650
702
  userId = utf8ToHex(userId);
651
- const a = leftPad2(utils3.numberToHexUnpadded(sm2Curve.CURVE.a), 64);
652
- const b = leftPad2(utils3.numberToHexUnpadded(sm2Curve.CURVE.b), 64);
653
- const gx = leftPad2(utils3.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64);
654
- const gy = leftPad2(utils3.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64);
703
+ const a = leftPad2(utils4.numberToHexUnpadded(sm2Curve.CURVE.a), 64);
704
+ const b = leftPad2(utils4.numberToHexUnpadded(sm2Curve.CURVE.b), 64);
705
+ const gx = leftPad2(utils4.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64);
706
+ const gy = leftPad2(utils4.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64);
655
707
  let px;
656
708
  let py;
657
709
  if (publicKey.length === 128) {
@@ -659,8 +711,8 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
659
711
  py = publicKey.substring(64, 128);
660
712
  } else {
661
713
  const point = sm2Curve.ProjectivePoint.fromHex(publicKey);
662
- px = leftPad2(utils3.numberToHexUnpadded(point.x), 64);
663
- py = leftPad2(utils3.numberToHexUnpadded(point.y), 64);
714
+ px = leftPad2(utils4.numberToHexUnpadded(point.x), 64);
715
+ py = leftPad2(utils4.numberToHexUnpadded(point.y), 64);
664
716
  }
665
717
  const data = hexToArray(userId + a + b + gx + gy + px + py);
666
718
  const entl = userId.length * 4;
@@ -669,13 +721,13 @@ function getHash(hashHex, publicKey, userId = "1234567812345678") {
669
721
  }
670
722
  function getPublicKeyFromPrivateKey(privateKey) {
671
723
  const pubKey = sm2Curve.getPublicKey(privateKey, false);
672
- const pubPad = leftPad2(utils3.bytesToHex(pubKey), 64);
724
+ const pubPad = leftPad2(utils4.bytesToHex(pubKey), 64);
673
725
  return pubPad;
674
726
  }
675
727
  function getPoint() {
676
728
  const keypair = generateKeyPairHex();
677
729
  const PA = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey);
678
- const k = utils3.hexToNumber(keypair.privateKey);
730
+ const k = utils4.hexToNumber(keypair.privateKey);
679
731
  return {
680
732
  ...keypair,
681
733
  k,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sm-crypto-v2",
3
- "version": "1.2.2",
3
+ "version": "1.4.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,15 @@
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
+ export { calculateSharedKey } from './kx'
13
+
11
14
  // const { G, curve, n } = generateEcparam()
12
15
  const C1C2C3 = 0
13
16
 
package/src/sm2/kx.ts ADDED
@@ -0,0 +1,76 @@
1
+ import { sm2Curve } from './ec';
2
+ import { KeyPair, concatArray, hexToArray, leftPad } from './utils';
3
+ import * as utils from '@noble/curves/abstract/utils';
4
+ import { Field } from '@noble/curves/abstract/modular';
5
+ import { sm3 } from './sm3';
6
+
7
+ export const field = Field(BigInt(sm2Curve.CURVE.n))
8
+
9
+ // 用到的常数
10
+ const wPow2 = utils.hexToNumber('80000000000000000000000000000000')
11
+ const wPow2Sub1 = utils.hexToNumber('7fffffffffffffffffffffffffffffff')
12
+
13
+ // from sm2 sign part, extracted for code reusable.
14
+ function hkdf(z: Uint8Array, keylen: number) {
15
+ let t = new Uint8Array() // 256 位
16
+ let msg = new Uint8Array(keylen)
17
+ let ct = 1
18
+ let offset = 0
19
+ const nextT = () => {
20
+ // (1) Hai = hash(z || ct)
21
+ // (2) ct++
22
+ t = sm3(Uint8Array.from([...z, ct >> 24 & 0x00ff, ct >> 16 & 0x00ff, ct >> 8 & 0x00ff, ct & 0x00ff]))
23
+ ct++
24
+ offset = 0
25
+ }
26
+ nextT() // 先生成 Ha1
27
+
28
+ for (let i = 0, len = msg.length; i < len; i++) {
29
+ // t = Ha1 || Ha2 || Ha3 || Ha4
30
+ if (offset === t.length) nextT()
31
+
32
+ // c2 = msg ^ t
33
+ msg[i] = t[offset++] & 0xff
34
+ }
35
+ return msg
36
+ }
37
+
38
+
39
+ export function calculateSharedKey(
40
+ keypairA: KeyPair,
41
+ ephemeralKeypairA: KeyPair,
42
+ publicKeyB: string,
43
+ ephemeralPublicKeyB: string,
44
+ idA: string = '1234567812345678',
45
+ idB: string = '1234567812345678',
46
+ sharedKeyLength: number,
47
+ ) {
48
+ const RA = sm2Curve.ProjectivePoint.fromHex(ephemeralKeypairA.publicKey)
49
+ const RB = sm2Curve.ProjectivePoint.fromHex(ephemeralPublicKeyB)
50
+ // const PA = sm2Curve.ProjectivePoint.fromHex(keypairA.publicKey) // 暂时用不到
51
+ const PB = sm2Curve.ProjectivePoint.fromHex(publicKeyB)
52
+ const ZA = hexToArray(idA)
53
+ const ZB = hexToArray(idB)
54
+ const rA = utils.hexToNumber(ephemeralKeypairA.privateKey)
55
+ const dA = utils.hexToNumber(keypairA.privateKey)
56
+ // 1.先算tA
57
+ const x1 = RA.x
58
+ // x1_ = 2^w + (x1 & (2^w - 1))
59
+ const x1_ = field.add(wPow2, (x1 & wPow2Sub1))
60
+ // tA = (dA + x1b * rA) mod n
61
+ const tA = field.add(dA, field.mul(x1_, rA))
62
+
63
+ // 2.算 U
64
+ // x2_ = 2^w + (x2 & (2^w - 1))
65
+ const x2 = RB.x
66
+ const x2_ = field.add(wPow2, (x2 & wPow2Sub1))
67
+ // U = [h * tA](PB + x2_ * RB)
68
+ const U = RB.multiply(x2_).add(PB).multiply(tA)
69
+
70
+ // 3.算 KDF
71
+ // KA = KDF(xU || yU || ZA || ZB, kLen)
72
+ const xU = hexToArray(leftPad(utils.numberToHexUnpadded(U.x), 64))
73
+ const yU = hexToArray(leftPad(utils.numberToHexUnpadded(U.y), 64))
74
+ const KA = hkdf(concatArray(xU, yU, ZA, ZB), sharedKeyLength)
75
+ return KA
76
+ }
package/src/sm2/utils.ts CHANGED
@@ -5,10 +5,15 @@ import { sm2Curve, sm2Fp } from './ec';
5
5
  import { mod } from '@noble/curves/abstract/modular';
6
6
  import { ONE, TWO, ZERO } from './bn';
7
7
 
8
+ export interface KeyPair {
9
+ privateKey: string
10
+ publicKey: string
11
+ }
12
+
8
13
  /**
9
14
  * 生成密钥对:publicKey = privateKey * G
10
15
  */
11
- export function generateKeyPairHex(str?: string) {
16
+ export function generateKeyPairHex(str?: string): KeyPair {
12
17
  const privateKey = str ? utils.numberToBytesBE((mod(BigInt(str), ONE) + ONE), 32) : sm2Curve.utils.randomPrivateKey()
13
18
  // const random = typeof a === 'string' ? new BigInteger(a, b) :
14
19
  // a ? new BigInteger(a, b!, c!) : new BigInteger(n.bitLength(), rng)