@agentunion/fastaun-browser 0.2.20 → 0.3.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.
Files changed (128) hide show
  1. package/CHANGELOG.md +66 -26
  2. package/README.md +0 -1
  3. package/_packed_docs/CHANGELOG.md +66 -26
  4. package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +542 -0
  5. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1 -24
  6. package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +419 -0
  7. package/_packed_docs/protocol/index.md +13 -3
  8. package/_packed_docs/python-sdk-v2-only-changelog.md +189 -0
  9. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +39 -16
  10. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +131 -39
  11. package/_packed_docs/sdk/09-message-rpc-manual.md +30 -67
  12. package/dist/auth.d.ts.map +1 -1
  13. package/dist/auth.js +25 -5
  14. package/dist/auth.js.map +1 -1
  15. package/dist/bundle.js +15042 -0
  16. package/dist/client.d.ts +179 -187
  17. package/dist/client.d.ts.map +1 -1
  18. package/dist/client.js +3148 -3993
  19. package/dist/client.js.map +1 -1
  20. package/dist/config.d.ts +0 -4
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +0 -4
  23. package/dist/config.js.map +1 -1
  24. package/dist/crypto.d.ts +8 -1
  25. package/dist/crypto.d.ts.map +1 -1
  26. package/dist/crypto.js +114 -1
  27. package/dist/crypto.js.map +1 -1
  28. package/dist/e2ee.d.ts +5 -210
  29. package/dist/e2ee.d.ts.map +1 -1
  30. package/dist/e2ee.js +4 -1379
  31. package/dist/e2ee.js.map +1 -1
  32. package/dist/index.d.ts +7 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +5 -4
  35. package/dist/index.js.map +1 -1
  36. package/dist/namespaces/auth.d.ts +9 -0
  37. package/dist/namespaces/auth.d.ts.map +1 -1
  38. package/dist/namespaces/auth.js +248 -4
  39. package/dist/namespaces/auth.js.map +1 -1
  40. package/dist/protected-headers.d.ts +14 -0
  41. package/dist/protected-headers.d.ts.map +1 -0
  42. package/dist/protected-headers.js +47 -0
  43. package/dist/protected-headers.js.map +1 -0
  44. package/dist/seq-tracker.d.ts +7 -2
  45. package/dist/seq-tracker.d.ts.map +1 -1
  46. package/dist/seq-tracker.js +33 -13
  47. package/dist/seq-tracker.js.map +1 -1
  48. package/dist/transport.d.ts +9 -1
  49. package/dist/transport.d.ts.map +1 -1
  50. package/dist/transport.js +262 -10
  51. package/dist/transport.js.map +1 -1
  52. package/dist/v2/crypto/aead.d.ts +26 -0
  53. package/dist/v2/crypto/aead.d.ts.map +1 -0
  54. package/dist/v2/crypto/aead.js +63 -0
  55. package/dist/v2/crypto/aead.js.map +1 -0
  56. package/dist/v2/crypto/canonical.d.ts +21 -0
  57. package/dist/v2/crypto/canonical.d.ts.map +1 -0
  58. package/dist/v2/crypto/canonical.js +111 -0
  59. package/dist/v2/crypto/canonical.js.map +1 -0
  60. package/dist/v2/crypto/dh-path.d.ts +21 -0
  61. package/dist/v2/crypto/dh-path.d.ts.map +1 -0
  62. package/dist/v2/crypto/dh-path.js +50 -0
  63. package/dist/v2/crypto/dh-path.js.map +1 -0
  64. package/dist/v2/crypto/ecdh.d.ts +19 -0
  65. package/dist/v2/crypto/ecdh.d.ts.map +1 -0
  66. package/dist/v2/crypto/ecdh.js +101 -0
  67. package/dist/v2/crypto/ecdh.js.map +1 -0
  68. package/dist/v2/crypto/ecdsa.d.ts +16 -0
  69. package/dist/v2/crypto/ecdsa.d.ts.map +1 -0
  70. package/dist/v2/crypto/ecdsa.js +52 -0
  71. package/dist/v2/crypto/ecdsa.js.map +1 -0
  72. package/dist/v2/crypto/hkdf.d.ts +21 -0
  73. package/dist/v2/crypto/hkdf.d.ts.map +1 -0
  74. package/dist/v2/crypto/hkdf.js +32 -0
  75. package/dist/v2/crypto/hkdf.js.map +1 -0
  76. package/dist/v2/crypto/index.d.ts +9 -0
  77. package/dist/v2/crypto/index.d.ts.map +1 -0
  78. package/dist/v2/crypto/index.js +8 -0
  79. package/dist/v2/crypto/index.js.map +1 -0
  80. package/dist/v2/crypto/recipients.d.ts +43 -0
  81. package/dist/v2/crypto/recipients.d.ts.map +1 -0
  82. package/dist/v2/crypto/recipients.js +188 -0
  83. package/dist/v2/crypto/recipients.js.map +1 -0
  84. package/dist/v2/e2ee/decrypt.d.ts +13 -0
  85. package/dist/v2/e2ee/decrypt.d.ts.map +1 -0
  86. package/dist/v2/e2ee/decrypt.js +176 -0
  87. package/dist/v2/e2ee/decrypt.js.map +1 -0
  88. package/dist/v2/e2ee/encrypt-group.d.ts +14 -0
  89. package/dist/v2/e2ee/encrypt-group.d.ts.map +1 -0
  90. package/dist/v2/e2ee/encrypt-group.js +196 -0
  91. package/dist/v2/e2ee/encrypt-group.js.map +1 -0
  92. package/dist/v2/e2ee/encrypt-p2p.d.ts +15 -0
  93. package/dist/v2/e2ee/encrypt-p2p.d.ts.map +1 -0
  94. package/dist/v2/e2ee/encrypt-p2p.js +240 -0
  95. package/dist/v2/e2ee/encrypt-p2p.js.map +1 -0
  96. package/dist/v2/e2ee/index.d.ts +9 -0
  97. package/dist/v2/e2ee/index.d.ts.map +1 -0
  98. package/dist/v2/e2ee/index.js +9 -0
  99. package/dist/v2/e2ee/index.js.map +1 -0
  100. package/dist/v2/e2ee/metadata-auth.d.ts +9 -0
  101. package/dist/v2/e2ee/metadata-auth.d.ts.map +1 -0
  102. package/dist/v2/e2ee/metadata-auth.js +60 -0
  103. package/dist/v2/e2ee/metadata-auth.js.map +1 -0
  104. package/dist/v2/e2ee/types.d.ts +57 -0
  105. package/dist/v2/e2ee/types.d.ts.map +1 -0
  106. package/dist/v2/e2ee/types.js +7 -0
  107. package/dist/v2/e2ee/types.js.map +1 -0
  108. package/dist/v2/session/index.d.ts +4 -0
  109. package/dist/v2/session/index.d.ts.map +1 -0
  110. package/dist/v2/session/index.js +3 -0
  111. package/dist/v2/session/index.js.map +1 -0
  112. package/dist/v2/session/keystore.d.ts +57 -0
  113. package/dist/v2/session/keystore.d.ts.map +1 -0
  114. package/dist/v2/session/keystore.js +244 -0
  115. package/dist/v2/session/keystore.js.map +1 -0
  116. package/dist/v2/session/session.d.ts +121 -0
  117. package/dist/v2/session/session.d.ts.map +1 -0
  118. package/dist/v2/session/session.js +344 -0
  119. package/dist/v2/session/session.js.map +1 -0
  120. package/dist/v2/state/commitment.d.ts +10 -0
  121. package/dist/v2/state/commitment.d.ts.map +1 -0
  122. package/dist/v2/state/commitment.js +86 -0
  123. package/dist/v2/state/commitment.js.map +1 -0
  124. package/dist/v2/state/index.d.ts +2 -0
  125. package/dist/v2/state/index.d.ts.map +1 -0
  126. package/dist/v2/state/index.js +2 -0
  127. package/dist/v2/state/index.js.map +1 -0
  128. package/package.json +8 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../../src/v2/crypto/canonical.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export declare const INFO_3DH: Uint8Array<ArrayBuffer>;
2
+ export declare const INFO_1DH: Uint8Array<ArrayBuffer>;
3
+ export declare const WRAP_KEY_LENGTH = 32;
4
+ /**
5
+ * 计算 3DH wrap_key。
6
+ *
7
+ * - DH1 = ECDH(sender_session_priv, recv_ik_pub)
8
+ * - DH2 = ECDH(sender_master_priv, recv_spk_pub)
9
+ * - DH3 = ECDH(sender_session_priv, recv_spk_pub)
10
+ * - ikm = DH1 || DH2 || DH3 (96B)
11
+ * - wrap_key = HKDF-SHA256(ikm, salt, "AUN-V2-3DH", 32)
12
+ */
13
+ export declare function compute3DHWrap(senderSessionPriv: Uint8Array, senderMasterPriv: Uint8Array, recvIKPub: Uint8Array, recvSPKPub: Uint8Array, salt: Uint8Array): Promise<Uint8Array>;
14
+ /**
15
+ * 计算 1DH wrap_key。
16
+ *
17
+ * - DH1 = ECDH(sender_session_priv, recv_ik_pub)
18
+ * - wrap_key = HKDF-SHA256(DH1, salt, "AUN-V2-1DH", 32)
19
+ */
20
+ export declare function compute1DHWrap(senderSessionPriv: Uint8Array, recvIKPub: Uint8Array, salt: Uint8Array): Promise<Uint8Array>;
21
+ //# sourceMappingURL=dh-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dh-path.d.ts","sourceRoot":"","sources":["../../../src/v2/crypto/dh-path.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,QAAQ,yBAAyC,CAAC;AAC/D,eAAO,MAAM,QAAQ,yBAAyC,CAAC;AAC/D,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,iBAAiB,EAAE,UAAU,EAC7B,gBAAgB,EAAE,UAAU,EAC5B,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAcrB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,iBAAiB,EAAE,UAAU,EAC7B,SAAS,EAAE,UAAU,EACrB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAMrB"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * AUN E2EE V2: DH 派生路径
3
+ *
4
+ * 规范引用: §3.1 / §5.2
5
+ * - 1DH: ECDH(sender_session_priv, recv_ik_pub) → HKDF
6
+ * - 3DH: 三个 ECDH 拼接 → HKDF
7
+ *
8
+ * 浏览器实现:组合 ecdh.ts + hkdf.ts。
9
+ */
10
+ import { ecdhComputeShared } from './ecdh';
11
+ import { hkdfSha256 } from './hkdf';
12
+ export const INFO_3DH = new TextEncoder().encode('AUN-V2-3DH');
13
+ export const INFO_1DH = new TextEncoder().encode('AUN-V2-1DH');
14
+ export const WRAP_KEY_LENGTH = 32;
15
+ /**
16
+ * 计算 3DH wrap_key。
17
+ *
18
+ * - DH1 = ECDH(sender_session_priv, recv_ik_pub)
19
+ * - DH2 = ECDH(sender_master_priv, recv_spk_pub)
20
+ * - DH3 = ECDH(sender_session_priv, recv_spk_pub)
21
+ * - ikm = DH1 || DH2 || DH3 (96B)
22
+ * - wrap_key = HKDF-SHA256(ikm, salt, "AUN-V2-3DH", 32)
23
+ */
24
+ export async function compute3DHWrap(senderSessionPriv, senderMasterPriv, recvIKPub, recvSPKPub, salt) {
25
+ const dh1 = await ecdhComputeShared(senderSessionPriv, recvIKPub);
26
+ const dh2 = await ecdhComputeShared(senderMasterPriv, recvSPKPub);
27
+ const dh3 = await ecdhComputeShared(senderSessionPriv, recvSPKPub);
28
+ if (dh1.length !== 32 || dh2.length !== 32 || dh3.length !== 32) {
29
+ throw new Error(`3DH expected 32B shares, got dh1=${dh1.length} dh2=${dh2.length} dh3=${dh3.length}`);
30
+ }
31
+ const ikm = new Uint8Array(96);
32
+ ikm.set(dh1, 0);
33
+ ikm.set(dh2, 32);
34
+ ikm.set(dh3, 64);
35
+ return hkdfSha256(ikm, salt, INFO_3DH, WRAP_KEY_LENGTH);
36
+ }
37
+ /**
38
+ * 计算 1DH wrap_key。
39
+ *
40
+ * - DH1 = ECDH(sender_session_priv, recv_ik_pub)
41
+ * - wrap_key = HKDF-SHA256(DH1, salt, "AUN-V2-1DH", 32)
42
+ */
43
+ export async function compute1DHWrap(senderSessionPriv, recvIKPub, salt) {
44
+ const dh1 = await ecdhComputeShared(senderSessionPriv, recvIKPub);
45
+ if (dh1.length !== 32) {
46
+ throw new Error(`1DH expected 32B share, got ${dh1.length}`);
47
+ }
48
+ return hkdfSha256(dh1, salt, INFO_1DH, WRAP_KEY_LENGTH);
49
+ }
50
+ //# sourceMappingURL=dh-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dh-path.js","sourceRoot":"","sources":["../../../src/v2/crypto/dh-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;AAC/D,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;AAC/D,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAElC;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,iBAA6B,EAC7B,gBAA4B,EAC5B,SAAqB,EACrB,UAAsB,EACtB,IAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;IACnE,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,oCAAoC,GAAG,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,CACrF,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAC/B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAChB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjB,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,iBAA6B,EAC7B,SAAqB,EACrB,IAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;IAClE,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 计算 ECDH 共享秘密(P-256 X 坐标,32 字节)。
3
+ *
4
+ * @param privateKeyScalar 私钥标量(32 字节 big-endian)
5
+ * @param peerPublicKeyDer 对端公钥(DER SubjectPublicKeyInfo 编码)
6
+ * @returns 32 字节共享秘密(椭圆曲线点 X 坐标)
7
+ */
8
+ export declare function ecdhComputeShared(privateKeyScalar: Uint8Array, peerPublicKeyDer: Uint8Array): Promise<Uint8Array>;
9
+ /**
10
+ * 生成 P-256 密钥对。
11
+ *
12
+ * @returns [privateKeyScalar 32B, publicKeyDer SubjectPublicKeyInfo]
13
+ */
14
+ export declare function generateP256Keypair(): Promise<[Uint8Array, Uint8Array]>;
15
+ /**
16
+ * 从私钥标量导出公钥 DER (SubjectPublicKeyInfo)。
17
+ */
18
+ export declare function privateToPublicDer(privateKeyScalar: Uint8Array): Promise<Uint8Array>;
19
+ //# sourceMappingURL=ecdh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecdh.d.ts","sourceRoot":"","sources":["../../../src/v2/crypto/ecdh.ts"],"names":[],"mappings":"AA0CA;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,gBAAgB,EAAE,UAAU,EAC5B,gBAAgB,EAAE,UAAU,GAC3B,OAAO,CAAC,UAAU,CAAC,CA6CrB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAe7E;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,gBAAgB,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAgB1F"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * AUN E2EE V2: ECDH P-256
3
+ *
4
+ * 规范引用: §3.1
5
+ * - 曲线: P-256 (secp256r1)
6
+ * - 输出: 椭圆曲线点 X 坐标字节(32 字节,无前缀)
7
+ *
8
+ * 浏览器实现:使用 WebCrypto (crypto.subtle) 完成 ECDH 派生。
9
+ * - 私钥输入是 32 字节 raw scalar,借助 @noble/curves 推算公钥点 (X, Y),
10
+ * 然后构造 JWK 格式导入 WebCrypto。
11
+ * - 公钥输入是 DER SubjectPublicKeyInfo,直接走 spki 导入。
12
+ * - deriveBits(256) 返回 32 字节 X 坐标,与 Python cryptography 库行为一致。
13
+ */
14
+ import { p256 } from '@noble/curves/nist.js';
15
+ /** base64url(无 padding)编码,用于 JWK 字段 */
16
+ function bytesToB64Url(bytes) {
17
+ let bin = '';
18
+ for (let i = 0; i < bytes.length; i++)
19
+ bin += String.fromCharCode(bytes[i]);
20
+ return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
21
+ }
22
+ /** base64url 解码 */
23
+ function b64UrlToBytes(s) {
24
+ const std = s.replace(/-/g, '+').replace(/_/g, '/');
25
+ const pad = std.length % 4 === 0 ? '' : '='.repeat(4 - (std.length % 4));
26
+ const bin = atob(std + pad);
27
+ const out = new Uint8Array(bin.length);
28
+ for (let i = 0; i < bin.length; i++)
29
+ out[i] = bin.charCodeAt(i);
30
+ return out;
31
+ }
32
+ /** 从 raw 32B scalar 推算 P-256 公钥的未压缩 (X, Y) 字节,各 32B */
33
+ function p256PublicXY(privateKeyScalar) {
34
+ // p256.getPublicKey(secretKey, isCompressed=false) → 65 字节 0x04 || X || Y
35
+ const pub = p256.getPublicKey(privateKeyScalar, false);
36
+ if (pub.length !== 65 || pub[0] !== 0x04) {
37
+ throw new Error(`unexpected uncompressed public key encoding: len=${pub.length}`);
38
+ }
39
+ return { x: pub.subarray(1, 33), y: pub.subarray(33, 65) };
40
+ }
41
+ /**
42
+ * 计算 ECDH 共享秘密(P-256 X 坐标,32 字节)。
43
+ *
44
+ * @param privateKeyScalar 私钥标量(32 字节 big-endian)
45
+ * @param peerPublicKeyDer 对端公钥(DER SubjectPublicKeyInfo 编码)
46
+ * @returns 32 字节共享秘密(椭圆曲线点 X 坐标)
47
+ */
48
+ export async function ecdhComputeShared(privateKeyScalar, peerPublicKeyDer) {
49
+ if (privateKeyScalar.length !== 32) {
50
+ throw new Error(`P-256 private scalar must be 32 bytes, got ${privateKeyScalar.length}`);
51
+ }
52
+ // 推算公钥点用于构造 JWK(WebCrypto 不接受 raw scalar)
53
+ const { x, y } = p256PublicXY(privateKeyScalar);
54
+ const privJwk = {
55
+ kty: 'EC',
56
+ crv: 'P-256',
57
+ d: bytesToB64Url(privateKeyScalar),
58
+ x: bytesToB64Url(x),
59
+ y: bytesToB64Url(y),
60
+ ext: true,
61
+ };
62
+ const privKey = await crypto.subtle.importKey('jwk', privJwk, { name: 'ECDH', namedCurve: 'P-256' }, false, ['deriveBits']);
63
+ const pubKey = await crypto.subtle.importKey('spki',
64
+ // BufferSource:copy 到独立 ArrayBuffer,避免传入 SharedArrayBuffer/视图歧义
65
+ peerPublicKeyDer.slice().buffer, { name: 'ECDH', namedCurve: 'P-256' }, false, []);
66
+ const sharedBits = await crypto.subtle.deriveBits({ name: 'ECDH', public: pubKey }, privKey, 256);
67
+ const out = new Uint8Array(sharedBits);
68
+ if (out.length !== 32) {
69
+ throw new Error(`ECDH derive returned ${out.length} bytes, expected 32`);
70
+ }
71
+ return out;
72
+ }
73
+ /**
74
+ * 生成 P-256 密钥对。
75
+ *
76
+ * @returns [privateKeyScalar 32B, publicKeyDer SubjectPublicKeyInfo]
77
+ */
78
+ export async function generateP256Keypair() {
79
+ const keyPair = await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveBits']);
80
+ const jwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey);
81
+ if (!jwk.d) {
82
+ throw new Error('exportKey(jwk) returned no private component');
83
+ }
84
+ const priv = b64UrlToBytes(jwk.d);
85
+ const pubDerBuf = await crypto.subtle.exportKey('spki', keyPair.publicKey);
86
+ return [priv, new Uint8Array(pubDerBuf)];
87
+ }
88
+ /**
89
+ * 从私钥标量导出公钥 DER (SubjectPublicKeyInfo)。
90
+ */
91
+ export async function privateToPublicDer(privateKeyScalar) {
92
+ if (privateKeyScalar.length !== 32) {
93
+ throw new Error(`P-256 private scalar must be 32 bytes, got ${privateKeyScalar.length}`);
94
+ }
95
+ const { x, y } = p256PublicXY(privateKeyScalar);
96
+ // 仅导入公钥点,再以 spki 导出
97
+ const pubKey = await crypto.subtle.importKey('jwk', { kty: 'EC', crv: 'P-256', x: bytesToB64Url(x), y: bytesToB64Url(y), ext: true }, { name: 'ECDH', namedCurve: 'P-256' }, true, []);
98
+ const der = await crypto.subtle.exportKey('spki', pubKey);
99
+ return new Uint8Array(der);
100
+ }
101
+ //# sourceMappingURL=ecdh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecdh.js","sourceRoot":"","sources":["../../../src/v2/crypto/ecdh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * ECDSA-SHA256 RAW 签名(RFC 6979 deterministic, r||s 64 字节)。
3
+ *
4
+ * @param privateKeyScalar 32 字节 P-256 私钥标量
5
+ * @param message 原始消息(noble 内部 SHA-256)
6
+ */
7
+ export declare function ecdsaSignRaw(privateKeyScalar: Uint8Array, message: Uint8Array): Promise<Uint8Array>;
8
+ /**
9
+ * ECDSA-SHA256 RAW 验签。
10
+ *
11
+ * @param publicKeyDer SPKI DER 公钥
12
+ * @param signatureRaw 64 字节 r||s
13
+ * @param message 原始消息(内部做 SHA-256)
14
+ */
15
+ export declare function ecdsaVerifyRaw(publicKeyDer: Uint8Array, signatureRaw: Uint8Array, message: Uint8Array): Promise<boolean>;
16
+ //# sourceMappingURL=ecdsa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecdsa.d.ts","sourceRoot":"","sources":["../../../src/v2/crypto/ecdsa.ts"],"names":[],"mappings":"AAeA;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,gBAAgB,EAAE,UAAU,EAC5B,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,YAAY,EAAE,UAAU,EACxB,YAAY,EAAE,UAAU,EACxB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,OAAO,CAAC,CAoBlB"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * AUN E2EE V2: ECDSA P-256 + SHA-256 RAW(r||s, 64B)
3
+ *
4
+ * 规范引用: §3.4 / §5.1 / §10
5
+ *
6
+ * 浏览器实现:
7
+ * - 签名:使用 @noble/curves p256(RFC 6979 deterministic),保持与 Python /
8
+ * Go SDK 字节一致。WebCrypto 的 ECDSA 签名是不确定性的(每次随机 k),
9
+ * 无法用于 golden 比对,因此签名走 noble。
10
+ * - 验签:用 WebCrypto subtle.verify,公钥从 SPKI DER 导入。
11
+ * - 哈希:noble p256.sign 默认 prehash=true(自带 SHA-256),与 Python /
12
+ * Go ECDSA-SHA256 行为一致;显式传 prehash 让意图更明确。
13
+ */
14
+ import { p256 } from '@noble/curves/nist.js';
15
+ /**
16
+ * ECDSA-SHA256 RAW 签名(RFC 6979 deterministic, r||s 64 字节)。
17
+ *
18
+ * @param privateKeyScalar 32 字节 P-256 私钥标量
19
+ * @param message 原始消息(noble 内部 SHA-256)
20
+ */
21
+ export async function ecdsaSignRaw(privateKeyScalar, message) {
22
+ if (privateKeyScalar.length !== 32) {
23
+ throw new Error(`ECDSA private key must be 32 bytes, got ${privateKeyScalar.length}`);
24
+ }
25
+ // noble v2: sign 直接返回 Uint8Array(默认 format='compact' 即 r||s 64B)
26
+ // lowS=false 与 Python cryptography / Go ecdsa 行为一致
27
+ const sig = p256.sign(message, privateKeyScalar, { lowS: false, prehash: true });
28
+ if (!(sig instanceof Uint8Array) || sig.length !== 64) {
29
+ throw new Error(`unexpected ECDSA signature shape: ${sig?.constructor?.name} len=${sig?.length}`);
30
+ }
31
+ return sig;
32
+ }
33
+ /**
34
+ * ECDSA-SHA256 RAW 验签。
35
+ *
36
+ * @param publicKeyDer SPKI DER 公钥
37
+ * @param signatureRaw 64 字节 r||s
38
+ * @param message 原始消息(内部做 SHA-256)
39
+ */
40
+ export async function ecdsaVerifyRaw(publicKeyDer, signatureRaw, message) {
41
+ if (signatureRaw.length !== 64)
42
+ return false;
43
+ try {
44
+ const pubKey = await crypto.subtle.importKey('spki', publicKeyDer.slice().buffer, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);
45
+ const ok = await crypto.subtle.verify({ name: 'ECDSA', hash: { name: 'SHA-256' } }, pubKey, signatureRaw.slice().buffer, message.slice().buffer);
46
+ return Boolean(ok);
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ //# sourceMappingURL=ecdsa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecdsa.js","sourceRoot":"","sources":["../../../src/v2/crypto/ecdsa.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,gBAA4B,EAC5B,OAAmB;IAEnB,IAAI,gBAAgB,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,2CAA2C,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,iEAAiE;IACjE,mDAAmD;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACjF,IAAI,CAAC,CAAC,GAAG,YAAY,UAAU,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,qCAAqC,GAAG,EAAE,WAAW,EAAE,IAAI,QAAS,GAA2B,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7H,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,YAAwB,EACxB,YAAwB,EACxB,OAAmB;IAEnB,IAAI,YAAY,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAC1C,MAAM,EACN,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAC3B,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EACtC,KAAK,EACL,CAAC,QAAQ,CAAC,CACX,CAAC;QACF,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CACnC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAC5C,MAAM,EACN,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAC3B,OAAO,CAAC,KAAK,EAAE,CAAC,MAAM,CACvB,CAAC;QACF,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * AUN E2EE V2: HKDF-SHA256
3
+ *
4
+ * 规范引用: §3.2 / §5.2 / §10
5
+ *
6
+ * 浏览器实现:使用 WebCrypto subtle.deriveBits 完成 HKDF。
7
+ * - salt 长度为 0 时按 RFC 5869 规则替换为 32 字节零(与 Python sdk 行为一致)。
8
+ * - info 必须是 BufferSource(Uint8Array 即可)。
9
+ * - 输出长度由 `length` 控制(字节数)。
10
+ */
11
+ /**
12
+ * 计算 HKDF-SHA256(ikm, salt, info, length)。
13
+ *
14
+ * @param ikm 输入密钥材料
15
+ * @param salt 盐(可空)
16
+ * @param info 上下文/信息字段
17
+ * @param length 输出字节数
18
+ * @returns 派生密钥
19
+ */
20
+ export declare function hkdfSha256(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Promise<Uint8Array>;
21
+ //# sourceMappingURL=hkdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hkdf.d.ts","sourceRoot":"","sources":["../../../src/v2/crypto/hkdf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,CAAC,CAqBrB"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * AUN E2EE V2: HKDF-SHA256
3
+ *
4
+ * 规范引用: §3.2 / §5.2 / §10
5
+ *
6
+ * 浏览器实现:使用 WebCrypto subtle.deriveBits 完成 HKDF。
7
+ * - salt 长度为 0 时按 RFC 5869 规则替换为 32 字节零(与 Python sdk 行为一致)。
8
+ * - info 必须是 BufferSource(Uint8Array 即可)。
9
+ * - 输出长度由 `length` 控制(字节数)。
10
+ */
11
+ /**
12
+ * 计算 HKDF-SHA256(ikm, salt, info, length)。
13
+ *
14
+ * @param ikm 输入密钥材料
15
+ * @param salt 盐(可空)
16
+ * @param info 上下文/信息字段
17
+ * @param length 输出字节数
18
+ * @returns 派生密钥
19
+ */
20
+ export async function hkdfSha256(ikm, salt, info, length) {
21
+ const realSalt = salt.length === 0 ? new Uint8Array(32) : salt;
22
+ // ikm 必须是独立 ArrayBuffer,避免视图歧义
23
+ const baseKey = await crypto.subtle.importKey('raw', ikm.slice().buffer, 'HKDF', false, ['deriveBits']);
24
+ const bits = await crypto.subtle.deriveBits({
25
+ name: 'HKDF',
26
+ hash: 'SHA-256',
27
+ salt: realSalt.slice().buffer,
28
+ info: info.slice().buffer,
29
+ }, baseKey, length * 8);
30
+ return new Uint8Array(bits);
31
+ }
32
+ //# sourceMappingURL=hkdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hkdf.js","sourceRoot":"","sources":["../../../src/v2/crypto/hkdf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAAe,EACf,IAAgB,EAChB,IAAgB,EAChB,MAAc;IAEd,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,+BAA+B;IAC/B,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAC3C,KAAK,EACL,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAClB,MAAM,EACN,KAAK,EACL,CAAC,YAAY,CAAC,CACf,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,UAAU,CACzC;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM;QAC7B,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM;KACZ,EACf,OAAO,EACP,MAAM,GAAG,CAAC,CACX,CAAC;IACF,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { canonicalJson } from './canonical';
2
+ export { ecdhComputeShared, generateP256Keypair, privateToPublicDer, } from './ecdh';
3
+ export { hkdfSha256 } from './hkdf';
4
+ export { aesGcmEncrypt, aesGcmDecrypt } from './aead';
5
+ export { ecdsaSignRaw, ecdsaVerifyRaw } from './ecdsa';
6
+ export { compute1DHWrap, compute3DHWrap, INFO_1DH, INFO_3DH, WRAP_KEY_LENGTH, } from './dh-path';
7
+ export { sortRecipients, computeLeafHash, computeMerkleRoot, computeMerkleProof, verifyMerkleProof, computeRecipientsDigest, } from './recipients';
8
+ export type { ProofStep } from './recipients';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/v2/crypto/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,EACL,cAAc,EACd,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { canonicalJson } from './canonical';
2
+ export { ecdhComputeShared, generateP256Keypair, privateToPublicDer, } from './ecdh';
3
+ export { hkdfSha256 } from './hkdf';
4
+ export { aesGcmEncrypt, aesGcmDecrypt } from './aead';
5
+ export { ecdsaSignRaw, ecdsaVerifyRaw } from './ecdsa';
6
+ export { compute1DHWrap, compute3DHWrap, INFO_1DH, INFO_3DH, WRAP_KEY_LENGTH, } from './dh-path';
7
+ export { sortRecipients, computeLeafHash, computeMerkleRoot, computeMerkleProof, verifyMerkleProof, computeRecipientsDigest, } from './recipients';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/v2/crypto/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,EACL,cAAc,EACd,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * AUN E2EE V2: Recipients 排序与 Digest(Merkle root)
3
+ *
4
+ * 规范引用: §10.3 / §5.3
5
+ * - 二维数组(无 columns 表头);行按 (aid asc, device_id asc, role asc) 排序
6
+ * - 每行固定 8 字段: [aid, device_id, role, key_source, fp, spk_id, wrap_nonce, wrapped_key]
7
+ * - leaf = SHA256(LEAF_PREFIX || canonical row binary fields)
8
+ * - inner = SHA256(NODE_PREFIX || left || right)
9
+ * - 奇数节点复制最后一个
10
+ *
11
+ * 浏览器实现:使用 WebCrypto subtle.digest('SHA-256'),全链路 async。
12
+ * - wrap_nonce / wrapped_key 字段:优先 base64 解码(仅当长度为 4 的倍数且字符合法),
13
+ * 失败时回退 UTF-8 字节,与 Python `_decode_or_raw` 对齐。
14
+ */
15
+ /**
16
+ * 按 (aid asc, device_id asc, role asc) 排序 recipients 行(不修改入参)。
17
+ */
18
+ export declare function sortRecipients(rows: string[][]): string[][];
19
+ /**
20
+ * 计算单个 recipient 行的 leaf hash(32 字节)。
21
+ */
22
+ export declare function computeLeafHash(row: string[]): Promise<Uint8Array>;
23
+ /**
24
+ * Merkle root(hex),rows 必须已排序。
25
+ */
26
+ export declare function computeMerkleRoot(rows: string[][]): Promise<string>;
27
+ export interface ProofStep {
28
+ sibling: string;
29
+ position: 'L' | 'R';
30
+ }
31
+ /**
32
+ * 为 targetIndex 行生成 Merkle proof。
33
+ */
34
+ export declare function computeMerkleProof(rows: string[][], targetIndex: number): Promise<ProofStep[]>;
35
+ /**
36
+ * 验证 leaf + proof 重建出的 root 与期望值一致。
37
+ */
38
+ export declare function verifyMerkleProof(leaf: Uint8Array, proof: ProofStep[], expectedRootHex: string): Promise<boolean>;
39
+ /**
40
+ * 计算 recipients_digest(Merkle root)。调用方 MUST 先调 sortRecipients。
41
+ */
42
+ export declare function computeRecipientsDigest(rows: string[][]): Promise<string>;
43
+ //# sourceMappingURL=recipients.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipients.d.ts","sourceRoot":"","sources":["../../../src/v2/crypto/recipients.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA8DH;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CAO3D;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CA8BxE;AAMD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAczE;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,GAAG,GAAG,GAAG,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EAAE,EAAE,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,EAAE,CAAC,CAsBtB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,SAAS,EAAE,EAClB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,OAAO,CAAC,CAelB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAE/E"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * AUN E2EE V2: Recipients 排序与 Digest(Merkle root)
3
+ *
4
+ * 规范引用: §10.3 / §5.3
5
+ * - 二维数组(无 columns 表头);行按 (aid asc, device_id asc, role asc) 排序
6
+ * - 每行固定 8 字段: [aid, device_id, role, key_source, fp, spk_id, wrap_nonce, wrapped_key]
7
+ * - leaf = SHA256(LEAF_PREFIX || canonical row binary fields)
8
+ * - inner = SHA256(NODE_PREFIX || left || right)
9
+ * - 奇数节点复制最后一个
10
+ *
11
+ * 浏览器实现:使用 WebCrypto subtle.digest('SHA-256'),全链路 async。
12
+ * - wrap_nonce / wrapped_key 字段:优先 base64 解码(仅当长度为 4 的倍数且字符合法),
13
+ * 失败时回退 UTF-8 字节,与 Python `_decode_or_raw` 对齐。
14
+ */
15
+ const LEAF_PREFIX = new TextEncoder().encode('AUN-V2-RCPT-LEAF-v1');
16
+ const NODE_PREFIX = new TextEncoder().encode('AUN-V2-RCPT-NODE-v1');
17
+ async function sha256(data) {
18
+ const buf = await crypto.subtle.digest('SHA-256', data.slice().buffer);
19
+ return new Uint8Array(buf);
20
+ }
21
+ function bytesToHex(b) {
22
+ let s = '';
23
+ for (let i = 0; i < b.length; i++)
24
+ s += b[i].toString(16).padStart(2, '0');
25
+ return s;
26
+ }
27
+ function hexToBytes(s) {
28
+ if (s.length % 2 !== 0)
29
+ throw new Error('hex length must be even');
30
+ const out = new Uint8Array(s.length / 2);
31
+ for (let i = 0; i < out.length; i++) {
32
+ const hi = parseInt(s.charAt(i * 2), 16);
33
+ const lo = parseInt(s.charAt(i * 2 + 1), 16);
34
+ if (Number.isNaN(hi) || Number.isNaN(lo))
35
+ throw new Error('invalid hex char');
36
+ out[i] = (hi << 4) | lo;
37
+ }
38
+ return out;
39
+ }
40
+ function concat(...arrs) {
41
+ let total = 0;
42
+ for (const a of arrs)
43
+ total += a.length;
44
+ const out = new Uint8Array(total);
45
+ let pos = 0;
46
+ for (const a of arrs) {
47
+ out.set(a, pos);
48
+ pos += a.length;
49
+ }
50
+ return out;
51
+ }
52
+ /**
53
+ * 与 Python `_decode_or_raw` 行为一致:
54
+ * - 空串 → 空 bytes
55
+ * - 长度为 4 的倍数且仅含 base64 字符 → atob 解码
56
+ * - 其他情况 → UTF-8 编码
57
+ */
58
+ function decodeOrRaw(value) {
59
+ if (!value)
60
+ return new Uint8Array(0);
61
+ // 标准 base64:A-Z a-z 0-9 + / =,长度必须是 4 的倍数
62
+ if (value.length > 0 && value.length % 4 === 0 && /^[A-Za-z0-9+/]+={0,2}$/.test(value)) {
63
+ try {
64
+ const bin = atob(value);
65
+ const out = new Uint8Array(bin.length);
66
+ for (let i = 0; i < bin.length; i++)
67
+ out[i] = bin.charCodeAt(i);
68
+ return out;
69
+ }
70
+ catch {
71
+ // fall through
72
+ }
73
+ }
74
+ return new TextEncoder().encode(value);
75
+ }
76
+ /**
77
+ * 按 (aid asc, device_id asc, role asc) 排序 recipients 行(不修改入参)。
78
+ */
79
+ export function sortRecipients(rows) {
80
+ return [...rows].sort((a, b) => {
81
+ if (a[0] !== b[0])
82
+ return a[0] < b[0] ? -1 : 1;
83
+ if (a[1] !== b[1])
84
+ return a[1] < b[1] ? -1 : 1;
85
+ if (a[2] !== b[2])
86
+ return a[2] < b[2] ? -1 : 1;
87
+ return 0;
88
+ });
89
+ }
90
+ /**
91
+ * 计算单个 recipient 行的 leaf hash(32 字节)。
92
+ */
93
+ export async function computeLeafHash(row) {
94
+ const enc = (s) => new TextEncoder().encode(s ?? '');
95
+ const aid = enc(String(row[0] ?? ''));
96
+ const deviceId = enc(String(row[1] ?? ''));
97
+ const role = enc(String(row[2] ?? ''));
98
+ const keySource = enc(String(row[3] ?? ''));
99
+ const fp = enc(String(row[4] ?? ''));
100
+ const spkId = enc(String(row.length > 5 ? row[5] : ''));
101
+ const wrapNonce = decodeOrRaw(row.length > 6 ? String(row[6] ?? '') : '');
102
+ const wrappedKey = decodeOrRaw(row.length > 7 ? String(row[7] ?? '') : '');
103
+ const ZERO = Uint8Array.of(0);
104
+ const data = concat(LEAF_PREFIX, aid, ZERO, deviceId, ZERO, role, ZERO, keySource, ZERO, fp, ZERO, spkId, ZERO, wrapNonce, wrappedKey);
105
+ return sha256(data);
106
+ }
107
+ async function nodeHash(left, right) {
108
+ return sha256(concat(NODE_PREFIX, left, right));
109
+ }
110
+ /**
111
+ * Merkle root(hex),rows 必须已排序。
112
+ */
113
+ export async function computeMerkleRoot(rows) {
114
+ if (rows.length === 0)
115
+ return '';
116
+ let layer = [];
117
+ for (const r of rows)
118
+ layer.push(await computeLeafHash(r));
119
+ while (layer.length > 1) {
120
+ if (layer.length % 2 === 1)
121
+ layer.push(layer[layer.length - 1]);
122
+ const next = [];
123
+ for (let i = 0; i < layer.length; i += 2) {
124
+ next.push(await nodeHash(layer[i], layer[i + 1]));
125
+ }
126
+ layer = next;
127
+ }
128
+ return bytesToHex(layer[0]);
129
+ }
130
+ /**
131
+ * 为 targetIndex 行生成 Merkle proof。
132
+ */
133
+ export async function computeMerkleProof(rows, targetIndex) {
134
+ if (rows.length === 0 || targetIndex < 0 || targetIndex >= rows.length)
135
+ return [];
136
+ let layer = [];
137
+ for (const r of rows)
138
+ layer.push(await computeLeafHash(r));
139
+ let idx = targetIndex;
140
+ const proof = [];
141
+ while (layer.length > 1) {
142
+ if (layer.length % 2 === 1)
143
+ layer.push(layer[layer.length - 1]);
144
+ const siblingIdx = idx ^ 1;
145
+ proof.push({
146
+ sibling: bytesToHex(layer[siblingIdx]),
147
+ position: siblingIdx > idx ? 'R' : 'L',
148
+ });
149
+ const next = [];
150
+ for (let i = 0; i < layer.length; i += 2) {
151
+ next.push(await nodeHash(layer[i], layer[i + 1]));
152
+ }
153
+ layer = next;
154
+ idx = Math.floor(idx / 2);
155
+ }
156
+ return proof;
157
+ }
158
+ /**
159
+ * 验证 leaf + proof 重建出的 root 与期望值一致。
160
+ */
161
+ export async function verifyMerkleProof(leaf, proof, expectedRootHex) {
162
+ if (!expectedRootHex)
163
+ return false;
164
+ let cur = leaf;
165
+ for (const step of proof) {
166
+ let sibling;
167
+ try {
168
+ sibling = hexToBytes(step.sibling);
169
+ }
170
+ catch {
171
+ return false;
172
+ }
173
+ if (step.position === 'L')
174
+ cur = await nodeHash(sibling, cur);
175
+ else if (step.position === 'R')
176
+ cur = await nodeHash(cur, sibling);
177
+ else
178
+ return false;
179
+ }
180
+ return bytesToHex(cur) === expectedRootHex;
181
+ }
182
+ /**
183
+ * 计算 recipients_digest(Merkle root)。调用方 MUST 先调 sortRecipients。
184
+ */
185
+ export async function computeRecipientsDigest(rows) {
186
+ return computeMerkleRoot(rows);
187
+ }
188
+ //# sourceMappingURL=recipients.js.map