sm-crypto-wasm 0.1.0 → 0.1.1

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/dist/sm2/index.js CHANGED
@@ -65,6 +65,24 @@ function getModule() {
65
65
  throw new Error('sm2: 未初始化,请先 `await ensureLoaded()`。');
66
66
  return mod;
67
67
  }
68
+ /**
69
+ * 现取 WASM memory 视图。
70
+ *
71
+ * **每次都用**,绝不在多次 `alloc` / wasm 调用之间缓存 `new Uint8Array(memory.buffer)`:
72
+ * 任何一次分配都可能让 WASM 堆增长(`memory.grow`),旧的 ArrayBuffer 会被 detach,
73
+ * 复用旧视图会抛 `TypeError: Cannot perform Construct on a detached ArrayBuffer`。
74
+ */
75
+ function memView() {
76
+ return new Uint8Array(getModule().memory.buffer);
77
+ }
78
+ /** 写入字节到 WASM 内存(现取视图)。 */
79
+ function putBytes(b, ptr) {
80
+ memView().set(b, ptr);
81
+ }
82
+ /** 读出 WASM 内存的拷贝(现取视图后 slice,不向上层交出会失效的视图)。 */
83
+ function readBytes(ptr, len) {
84
+ return new Uint8Array(getModule().memory.buffer, ptr, len).slice();
85
+ }
68
86
  /**
69
87
  * 从私钥派生公钥。
70
88
  *
@@ -80,13 +98,13 @@ export function getPublicKey(privateKey) {
80
98
  * `getPublicKey` 与缓存未命中时的 `derivePublicKeyBytes` 都走这里。
81
99
  */
82
100
  function derivePublicKeyRaw(d) {
83
- const { exports, memory } = getModule();
101
+ const { exports } = getModule();
84
102
  const dp = exports.alloc(32);
85
103
  const op = exports.alloc(64);
86
104
  try {
87
- new Uint8Array(memory.buffer).set(d, dp);
105
+ putBytes(d, dp);
88
106
  exports.publicKeyOut(dp, op);
89
- return new Uint8Array(memory.buffer, op, 64).slice();
107
+ return readBytes(op, 64);
90
108
  }
91
109
  finally {
92
110
  exports.freeAll();
@@ -209,7 +227,6 @@ export function sign(privateKey, message) {
209
227
  const m = toBytes(message, 'message');
210
228
  const pub = derivePublicKeyBytes(d);
211
229
  const { exports } = getModule();
212
- const mem = new Uint8Array(getModule().memory.buffer);
213
230
  const dp = exports.alloc(32);
214
231
  const pxp = exports.alloc(32);
215
232
  const pyp = exports.alloc(32);
@@ -217,17 +234,17 @@ export function sign(privateKey, message) {
217
234
  const kp = exports.alloc(32);
218
235
  const op = exports.alloc(64);
219
236
  try {
220
- mem.set(d, dp);
221
- mem.set(pub.subarray(0, 32), pxp);
222
- mem.set(pub.subarray(32, 64), pyp);
223
- mem.set(m, mp);
237
+ putBytes(d, dp);
238
+ putBytes(pub.subarray(0, 32), pxp);
239
+ putBytes(pub.subarray(32, 64), pyp);
240
+ putBytes(m, mp);
224
241
  // 最多重试几次 k(极小概率 r/s 为 0 或 r+k==n)。
225
242
  for (let attempt = 0; attempt < 16; attempt++) {
226
243
  const k = randomK();
227
- mem.set(k, kp);
244
+ putBytes(k, kp);
228
245
  const rc = exports.signOut(dp, pxp, pyp, mp, m.length, kp, op);
229
246
  if (rc === 0) {
230
- return fromBytes(new Uint8Array(mem.buffer, op, 64).slice(), 'hex');
247
+ return fromBytes(readBytes(op, 64), 'hex');
231
248
  }
232
249
  }
233
250
  throw new Error('sm2.sign: failed to produce a valid signature after retries');
@@ -251,16 +268,15 @@ export function verify(publicKey, message, signature) {
251
268
  if (sig.length !== 64)
252
269
  throw new InvalidCiphertextError('sm2: signature must be 64 bytes');
253
270
  const { exports } = getModule();
254
- const mem = new Uint8Array(getModule().memory.buffer);
255
271
  const pxp = exports.alloc(32);
256
272
  const pyp = exports.alloc(32);
257
273
  const mp = exports.alloc(m.length);
258
274
  const sigp = exports.alloc(64);
259
275
  try {
260
- mem.set(x, pxp);
261
- mem.set(y, pyp);
262
- mem.set(m, mp);
263
- mem.set(sig, sigp);
276
+ putBytes(x, pxp);
277
+ putBytes(y, pyp);
278
+ putBytes(m, mp);
279
+ putBytes(sig, sigp);
264
280
  return exports.verifyOut(pxp, pyp, mp, m.length, sigp) === 1;
265
281
  }
266
282
  finally {
@@ -286,21 +302,20 @@ export function encrypt(publicKey, message, opts = {}) {
286
302
  }
287
303
  const m = toBytes(message, 'message');
288
304
  const { exports } = getModule();
289
- const mem = new Uint8Array(getModule().memory.buffer);
290
305
  const pxp = exports.alloc(32);
291
306
  const pyp = exports.alloc(32);
292
307
  const mp = exports.alloc(m.length);
293
308
  const kp = exports.alloc(32);
294
309
  const ctp = exports.alloc(97 + m.length);
295
310
  try {
296
- mem.set(x, pxp);
297
- mem.set(y, pyp);
298
- mem.set(m, mp);
311
+ putBytes(x, pxp);
312
+ putBytes(y, pyp);
313
+ putBytes(m, mp);
299
314
  for (let attempt = 0; attempt < 16; attempt++) {
300
- mem.set(randomK(), kp);
315
+ putBytes(randomK(), kp);
301
316
  const rc = exports.encryptOut(pxp, pyp, mp, m.length, kp, ctp);
302
317
  if (rc === 1) {
303
- const raw = new Uint8Array(mem.buffer, ctp, 97 + m.length).slice();
318
+ const raw = readBytes(ctp, 97 + m.length);
304
319
  return fromBytes(format === 'C1C2C3' ? c1c3c2ToC1c2c3(raw) : raw, 'hex');
305
320
  }
306
321
  }
@@ -354,18 +369,17 @@ function decryptUnsafe(privateKey, ciphertext, opts) {
354
369
  /** 按 C1C3C2 布局解密(wasm 侧约定的布局)。 */
355
370
  function decryptRaw(d, ct) {
356
371
  const { exports } = getModule();
357
- const mem = new Uint8Array(getModule().memory.buffer);
358
372
  const dp = exports.alloc(32);
359
373
  const ctp = exports.alloc(ct.length);
360
374
  const outLen = ct.length - 97;
361
375
  const ptp = exports.alloc(outLen === 0 ? 1 : outLen);
362
376
  try {
363
- mem.set(d, dp);
364
- mem.set(ct, ctp);
377
+ putBytes(d, dp);
378
+ putBytes(ct, ctp);
365
379
  const rc = exports.decryptOut(dp, ctp, ct.length, ptp);
366
380
  if (rc !== 1)
367
381
  throw new DecryptionError('sm2.decrypt: C3 verification failed');
368
- return fromBytes(new Uint8Array(mem.buffer, ptp, outLen).slice(), 'hex');
382
+ return fromBytes(readBytes(ptp, outLen), 'hex');
369
383
  }
370
384
  finally {
371
385
  exports.freeAll();
package/dist/sm4/index.js CHANGED
@@ -34,7 +34,7 @@ function withBuffers(key, data, outLen, fn) {
34
34
  const mem = new Uint8Array(memory.buffer);
35
35
  mem.set(key, keyPtr);
36
36
  mem.set(data, inPtr);
37
- return fn(keyPtr, inPtr, outPtr, new Uint8Array(memory.buffer));
37
+ return fn(keyPtr, inPtr, outPtr);
38
38
  }
39
39
  finally {
40
40
  exports.freeAll();
@@ -244,7 +244,7 @@ function withGcmBuffers(k, v, a, data, fn) {
244
244
  mem.set(a, aadPtr);
245
245
  if (data.length !== 0)
246
246
  mem.set(data, inPtr);
247
- return fn({ keyPtr, ivPtr, aadPtr, inPtr, outPtr, tagPtr }, mem);
247
+ return fn({ keyPtr, ivPtr, aadPtr, inPtr, outPtr, tagPtr });
248
248
  }
249
249
  finally {
250
250
  exports.freeAll();
package/dist/sm9/index.js CHANGED
@@ -354,17 +354,21 @@ export function encrypt(publicKey, id, msg, r) {
354
354
  const idP = exports.alloc(idB.length);
355
355
  const msgP = exports.alloc(msgB.length);
356
356
  const rP = exports.alloc(32);
357
- const ctP = exports.alloc(4096);
357
+ // 密文布局 C1(65) || C3(32) || C2(|msg|),长度随明文增长 —— 按实际长度分配,
358
+ // 并把容量一并交给 wasm 侧校验。曾硬编码 alloc(4096):明文超过 3999 字节时
359
+ // sm9Encrypt 会写越界、破坏 GC 堆(几轮后 RuntimeError: memory access out of bounds)。
360
+ const ctCap = 65 + 32 + msgB.length;
361
+ const ctP = exports.alloc(ctCap);
358
362
  try {
359
363
  putBytes(key.bytes, keyP);
360
364
  putBytes(idB, idP);
361
365
  putBytes(msgB, msgP);
362
366
  putBytes(rB, rP);
363
367
  const ctLen = key.kind === 'public'
364
- ? exports.sm9EncryptPubOut(keyP, idP, idB.length, msgP, msgB.length, rP, ctP)
365
- : exports.sm9EncryptOut(keyP, idP, idB.length, msgP, msgB.length, rP, ctP);
368
+ ? exports.sm9EncryptPubOut(keyP, idP, idB.length, msgP, msgB.length, rP, ctP, ctCap)
369
+ : exports.sm9EncryptOut(keyP, idP, idB.length, msgP, msgB.length, rP, ctP, ctCap);
366
370
  if (ctLen < 0)
367
- throw new Error('sm9: encrypt 失败');
371
+ throw new Error('sm9: encrypt 失败(密文缓冲容量不足)');
368
372
  return readHex(ctP, ctLen);
369
373
  }
370
374
  finally {
package/dist/sm9/sm9.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sm-crypto-wasm",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "国密 SM2/SM3/SM4/SM9/ZUC 的 WASM 实现,Node 18+ 与现代浏览器均可使用,按算法分包懒加载。",
5
5
  "description:en": "SM2/SM3/SM4/SM9/ZUC (China crypto) implemented in AssemblyScript -> WASM. Node 18+ & modern browsers, per-algorithm lazy loading.",
6
6
  "license": "Apache-2.0",