@trustbaseai/account 0.1.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.
Files changed (62) hide show
  1. package/README.md +351 -0
  2. package/dist/address.d.ts +70 -0
  3. package/dist/address.d.ts.map +1 -0
  4. package/dist/address.js +104 -0
  5. package/dist/address.js.map +1 -0
  6. package/dist/bech32.d.ts +78 -0
  7. package/dist/bech32.d.ts.map +1 -0
  8. package/dist/bech32.js +246 -0
  9. package/dist/bech32.js.map +1 -0
  10. package/dist/bytes.d.ts +88 -0
  11. package/dist/bytes.d.ts.map +1 -0
  12. package/dist/bytes.js +215 -0
  13. package/dist/bytes.js.map +1 -0
  14. package/dist/envelope.d.ts +116 -0
  15. package/dist/envelope.d.ts.map +1 -0
  16. package/dist/envelope.js +237 -0
  17. package/dist/envelope.js.map +1 -0
  18. package/dist/errors.d.ts +48 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +41 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/hd.d.ts +85 -0
  23. package/dist/hd.d.ts.map +1 -0
  24. package/dist/hd.js +112 -0
  25. package/dist/hd.js.map +1 -0
  26. package/dist/index.d.ts +60 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +199 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/kdf.d.ts +163 -0
  31. package/dist/kdf.d.ts.map +1 -0
  32. package/dist/kdf.js +351 -0
  33. package/dist/kdf.js.map +1 -0
  34. package/dist/keys.d.ts +55 -0
  35. package/dist/keys.d.ts.map +1 -0
  36. package/dist/keys.js +114 -0
  37. package/dist/keys.js.map +1 -0
  38. package/dist/keystore.d.ts +168 -0
  39. package/dist/keystore.d.ts.map +1 -0
  40. package/dist/keystore.js +340 -0
  41. package/dist/keystore.js.map +1 -0
  42. package/dist/mnemonic.d.ts +84 -0
  43. package/dist/mnemonic.d.ts.map +1 -0
  44. package/dist/mnemonic.js +199 -0
  45. package/dist/mnemonic.js.map +1 -0
  46. package/dist/password.d.ts +79 -0
  47. package/dist/password.d.ts.map +1 -0
  48. package/dist/password.js +237 -0
  49. package/dist/password.js.map +1 -0
  50. package/dist/prf-webauthn.d.ts +85 -0
  51. package/dist/prf-webauthn.d.ts.map +1 -0
  52. package/dist/prf-webauthn.js +204 -0
  53. package/dist/prf-webauthn.js.map +1 -0
  54. package/dist/prf.d.ts +157 -0
  55. package/dist/prf.d.ts.map +1 -0
  56. package/dist/prf.js +318 -0
  57. package/dist/prf.js.map +1 -0
  58. package/dist/webcrypto.d.ts +93 -0
  59. package/dist/webcrypto.d.ts.map +1 -0
  60. package/dist/webcrypto.js +157 -0
  61. package/dist/webcrypto.js.map +1 -0
  62. package/package.json +51 -0
package/dist/bech32.js ADDED
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ /**
3
+ * bech32(BIP-173)纯 JS 实现 —— 只做编码/解码,不做 bech32m。
4
+ *
5
+ * ## 为什么自己写
6
+ *
7
+ * 地址口径是**红线**(入口文档 §8.3.2 ①②:「买家标识必须是合法账户地址」),
8
+ * 而 bech32 的输入只有 20 字节 payload + 一个 HRP。自己实现的代码量约 80 行,
9
+ * 换来的是:零 Node 依赖(浏览器/Node 同一份)、零打包体积负担、以及
10
+ * **可以被公开向量与 cosmjs 双侧对着测**。反过来引一个通用 bech32 库,
11
+ * 它默认可能给的是 bech32m、可能对大小写做沉默归一 —— 这两件事都会让
12
+ * "派生出的地址链上不认",而症状只在转账时才出现。
13
+ *
14
+ * ## 与 BIP-173 的取舍(照抄标准,不做宽容)
15
+ *
16
+ * | 规则 | 本实现 |
17
+ * |---|---|
18
+ * | 校验和常量 | `1`(bech32)。**不用 bech32m 的 `0x2bc830a3`** —— Cosmos 账户地址是 bech32 |
19
+ * | 大小写 | 全小写或全大写都收(解码后归一为小写),**混用直接拒**(BIP-173 明确禁止) |
20
+ * | 长度 | 总长 ≤ 90 字符(BIP-173 的硬上限) |
21
+ * | 数据部分 | 只能是 32 个字符集内的字符;`1` 是分隔符,不出现在数据里 |
22
+ * | 填充位 | `convertBits(..., pad=false)` 时校验剩余位必须为 0(否则是"非规范编码",拒) |
23
+ *
24
+ * 参考实现出处:BIP-173 附录的 C 参考代码(Sipa 的 `ref/python/segwit_addr.py`
25
+ * 与 `ref/c/segwit_addr.c`,均为 MIT/公有领域),逻辑等价、改写为 TS +
26
+ * `Uint8Array`,并把"非法输入直接抛错"改成显式错误码。
27
+ *
28
+ * ## 来源与真源
29
+ *
30
+ * HRP 的取值以 `@trustbase/protocol` 的 `BECH32_PREFIX` 为准(本包同值声明,
31
+ * 漂移由 `test/constants-drift.test.ts` 静态守着)。
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.BECH32_CHARSET = exports.BECH32_MAX_LENGTH = void 0;
35
+ exports.bech32Polymod = bech32Polymod;
36
+ exports.bech32HrpExpand = bech32HrpExpand;
37
+ exports.bech32Encode = bech32Encode;
38
+ exports.bech32Decode = bech32Decode;
39
+ exports.convertBits = convertBits;
40
+ exports.encodeBech32Address = encodeBech32Address;
41
+ exports.decodeBech32Address = decodeBech32Address;
42
+ const errors_1 = require("./errors");
43
+ /** BIP-173 的总长度上限(含 HRP、分隔符、数据、校验和) */
44
+ exports.BECH32_MAX_LENGTH = 90;
45
+ /** bech32 数据字符集(32 个字符,索引即 5 bit 值) */
46
+ exports.BECH32_CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
47
+ /** 校验和常量:bech32 = 1,bech32m = 0x2bc830a3(本包只用前者) */
48
+ const BECH32_CONST = 1;
49
+ const BECH32M_CONST = 0x2bc830a3;
50
+ const GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
51
+ const CHARSET_LOOKUP = (() => {
52
+ const table = {};
53
+ for (let i = 0; i < exports.BECH32_CHARSET.length; i++) {
54
+ table[exports.BECH32_CHARSET.charAt(i)] = i;
55
+ }
56
+ return table;
57
+ })();
58
+ /** BIP-173 的 checksum 多项式求值(输入是 5 bit 值序列) */
59
+ function bech32Polymod(values) {
60
+ let checksum = 1;
61
+ for (const value of values) {
62
+ const top = checksum >> 25;
63
+ checksum = ((checksum & 0x1ffffff) << 5) ^ value;
64
+ for (let i = 0; i < 5; i++) {
65
+ if (((top >> i) & 1) === 1) {
66
+ checksum ^= GENERATOR[i] ?? 0;
67
+ }
68
+ }
69
+ }
70
+ return checksum;
71
+ }
72
+ /** HRP 展开:每个字符取高 3 bit,插入 0,再取低 5 bit */
73
+ function bech32HrpExpand(hrp) {
74
+ const out = [];
75
+ for (let i = 0; i < hrp.length; i++) {
76
+ out.push(hrp.charCodeAt(i) >> 5);
77
+ }
78
+ out.push(0);
79
+ for (let i = 0; i < hrp.length; i++) {
80
+ out.push(hrp.charCodeAt(i) & 31);
81
+ }
82
+ return out;
83
+ }
84
+ function bech32CreateChecksum(hrp, data) {
85
+ const values = [...bech32HrpExpand(hrp), ...data, 0, 0, 0, 0, 0, 0];
86
+ const polymod = bech32Polymod(values) ^ BECH32_CONST;
87
+ const out = [];
88
+ for (let i = 0; i < 6; i++) {
89
+ out.push((polymod >> (5 * (5 - i))) & 31);
90
+ }
91
+ return out;
92
+ }
93
+ function assertHrp(hrp) {
94
+ if (typeof hrp !== 'string' || hrp.length === 0) {
95
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'bech32 的 HRP 不能为空');
96
+ }
97
+ if (hrp.length + 7 > exports.BECH32_MAX_LENGTH) {
98
+ throw new errors_1.AccountError('INVALID_ARGUMENT', `bech32 的 HRP 过长(总长上限 ${exports.BECH32_MAX_LENGTH})`);
99
+ }
100
+ for (let i = 0; i < hrp.length; i++) {
101
+ const code = hrp.charCodeAt(i);
102
+ // 33..126 是 BIP-173 允许的可打印 ASCII 区间(同时天然排除大写混用问题)
103
+ if (code < 33 || code > 126) {
104
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'bech32 的 HRP 只能是可打印 ASCII(33..126)');
105
+ }
106
+ }
107
+ if (hrp !== hrp.toLowerCase()) {
108
+ throw new errors_1.AccountError('INVALID_ARGUMENT', '本实现只接受小写 HRP(大写输出会让地址在不同钱包里显示不一致)');
109
+ }
110
+ }
111
+ /**
112
+ * bech32 编码(BIP-173)。`data` 是 5 bit 值序列(每项 0..31)。
113
+ *
114
+ * 输入是大写 HRP 或含非法值时抛 `INVALID_ARGUMENT`。输出恒为小写。
115
+ */
116
+ function bech32Encode(hrp, data) {
117
+ assertHrp(hrp);
118
+ const words = [];
119
+ for (const value of data) {
120
+ if (!Number.isInteger(value) || value < 0 || value > 31) {
121
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'bech32 数据部分必须是 0..31 的 5 bit 值');
122
+ }
123
+ words.push(value);
124
+ }
125
+ const combined = [...words, ...bech32CreateChecksum(hrp, words)];
126
+ if (hrp.length + 1 + combined.length > exports.BECH32_MAX_LENGTH) {
127
+ throw new errors_1.AccountError('INVALID_ARGUMENT', `bech32 总长超过 ${exports.BECH32_MAX_LENGTH} 字符上限`);
128
+ }
129
+ let out = `${hrp}1`;
130
+ for (const value of combined) {
131
+ out += exports.BECH32_CHARSET.charAt(value);
132
+ }
133
+ return out;
134
+ }
135
+ /**
136
+ * bech32 解码。校验和不匹配 / 大小写混用 / 超长 / 缺分隔符 / 数据含非法字符
137
+ * 一律抛 `INVALID_BLOB`(这是"外来字符串不合法"的类别,与"编程错误"分开)。
138
+ */
139
+ function bech32Decode(value) {
140
+ if (typeof value !== 'string') {
141
+ throw new errors_1.AccountError('INVALID_BLOB', 'bech32 输入必须是字符串');
142
+ }
143
+ if (value.length === 0 || value.length > exports.BECH32_MAX_LENGTH) {
144
+ throw new errors_1.AccountError('INVALID_BLOB', `bech32 长度必须在 1..${exports.BECH32_MAX_LENGTH} 之间`);
145
+ }
146
+ const hasLower = value !== value.toUpperCase();
147
+ const hasUpper = value !== value.toLowerCase();
148
+ if (hasLower && hasUpper) {
149
+ throw new errors_1.AccountError('INVALID_BLOB', 'bech32 不允许大小写混用(BIP-173)');
150
+ }
151
+ const normalized = value.toLowerCase();
152
+ const separator = normalized.lastIndexOf('1');
153
+ if (separator < 1 || separator + 7 > normalized.length) {
154
+ // 分隔符位置非法:要么在最前(空 HRP),要么后面不足 6 字符校验和
155
+ throw new errors_1.AccountError('INVALID_BLOB', 'bech32 的分隔符位置非法(需有非空 HRP 与 6 字符校验和)');
156
+ }
157
+ const hrp = normalized.slice(0, separator);
158
+ for (let i = 0; i < hrp.length; i++) {
159
+ const code = hrp.charCodeAt(i);
160
+ if (code < 33 || code > 126) {
161
+ throw new errors_1.AccountError('INVALID_BLOB', 'bech32 的 HRP 只能是可打印 ASCII(33..126)');
162
+ }
163
+ }
164
+ const dataChars = normalized.slice(separator + 1);
165
+ const data = [];
166
+ for (let i = 0; i < dataChars.length; i++) {
167
+ const word = CHARSET_LOOKUP[dataChars.charAt(i)];
168
+ if (word === undefined) {
169
+ throw new errors_1.AccountError('INVALID_BLOB', `bech32 数据部分含非法字符:${dataChars.charAt(i)}`);
170
+ }
171
+ data.push(word);
172
+ }
173
+ const polymod = bech32Polymod([...bech32HrpExpand(hrp), ...data]);
174
+ if (polymod === BECH32_CONST) {
175
+ return { hrp, data: data.slice(0, -6) };
176
+ }
177
+ if (polymod === BECH32M_CONST) {
178
+ // 明确区分:bech32m 是链上/钱包里另一端常见的写法,报"校验和不匹配"会误导排查
179
+ throw new errors_1.AccountError('INVALID_BLOB', '这是 bech32m 编码,不是 bech32(账户地址必须是 bech32)');
180
+ }
181
+ throw new errors_1.AccountError('INVALID_BLOB', 'bech32 校验和不匹配(字符串被改过或抄错)');
182
+ }
183
+ /**
184
+ * 8 bit ↔ 5 bit 重新分组(BIP-173 `convertbits`)。
185
+ *
186
+ * `pad=true` 时末组左移补零(编码方向);`pad=false` 时要求末组不使用填充位
187
+ * 且剩余位为 0,否则抛错(解码方向)—— 放宽这条会让同一段 payload 有多种
188
+ * 等价编码,等于给地址留了别名。
189
+ */
190
+ function convertBits(data, from, to, pad) {
191
+ let accumulator = 0;
192
+ let bits = 0;
193
+ const out = [];
194
+ const maxValue = (1 << to) - 1;
195
+ const maxAccumulator = (1 << (from + to - 1)) - 1;
196
+ for (const value of data) {
197
+ if (!Number.isInteger(value) || value < 0 || value >> from !== 0) {
198
+ throw new errors_1.AccountError('INVALID_ARGUMENT', `convertBits 输入值超出 ${from} bit 范围`);
199
+ }
200
+ accumulator = ((accumulator << from) | value) & maxAccumulator;
201
+ bits += from;
202
+ while (bits >= to) {
203
+ bits -= to;
204
+ out.push((accumulator >> bits) & maxValue);
205
+ }
206
+ }
207
+ if (pad) {
208
+ if (bits > 0)
209
+ out.push((accumulator << (to - bits)) & maxValue);
210
+ }
211
+ else if (bits >= from || ((accumulator << (to - bits)) & maxValue) !== 0) {
212
+ throw new errors_1.AccountError('INVALID_BLOB', 'convertBits 存在非零填充位(非规范编码)');
213
+ }
214
+ return out;
215
+ }
216
+ /**
217
+ * 账户地址编码:`hrp1<8→5 bit 重分组><校验和>`。
218
+ * 不做长度假设(20 字节是账户地址的约定,由 address.ts 把关)。
219
+ */
220
+ function encodeBech32Address(hrp, payload) {
221
+ if (!(payload instanceof Uint8Array) || payload.length === 0) {
222
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'bech32 地址的 payload 不能为空');
223
+ }
224
+ return bech32Encode(hrp, convertBits(payload, 8, 5, true));
225
+ }
226
+ /**
227
+ * 账户地址解码:返回 HRP 与原始字节 payload。
228
+ * 若给了 `expectedHrp`,HRP 不匹配时抛错(大小写已归一,故不会被大写骗过)。
229
+ */
230
+ function decodeBech32Address(value, expectedHrp) {
231
+ const { hrp, data } = bech32Decode(value);
232
+ if (expectedHrp !== undefined) {
233
+ if (expectedHrp !== expectedHrp.toLowerCase()) {
234
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'expectedHrp 必须是小写');
235
+ }
236
+ if (hrp !== expectedHrp) {
237
+ throw new errors_1.AccountError('INVALID_BLOB', `地址前缀不是 ${expectedHrp}(实际 ${hrp})`);
238
+ }
239
+ }
240
+ const bytes = convertBits(data, 5, 8, false);
241
+ if (bytes.length === 0) {
242
+ throw new errors_1.AccountError('INVALID_BLOB', '地址 payload 为空');
243
+ }
244
+ return { hrp, payload: Uint8Array.from(bytes) };
245
+ }
246
+ //# sourceMappingURL=bech32.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bech32.js","sourceRoot":"","sources":["../src/bech32.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;;;AAsBH,sCAYC;AAGD,0CAUC;AAoCD,oCAkBC;AAaD,oCA2CC;AASD,kCAuBC;AAMD,kDAKC;AAMD,kDAeC;AA3ND,qCAAwC;AAExC,uCAAuC;AAC1B,QAAA,iBAAiB,GAAG,EAAE,CAAC;AACpC,uCAAuC;AAC1B,QAAA,cAAc,GAAG,kCAAkC,CAAC;AACjE,oDAAoD;AACpD,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,MAAM,aAAa,GAAG,UAAU,CAAC;AACjC,MAAM,SAAS,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAE/E,MAAM,cAAc,GAAqC,CAAC,GAAG,EAAE;IAC7D,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,sBAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,KAAK,CAAC,sBAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC,EAAE,CAAC;AAEL,8CAA8C;AAC9C,SAAgB,aAAa,CAAC,MAAyB;IACrD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,QAAQ,IAAI,EAAE,CAAC;QAC3B,QAAQ,GAAG,CAAC,CAAC,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;QACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3B,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,yCAAyC;AACzC,SAAgB,eAAe,CAAC,GAAW;IACzC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAW,EAAE,IAAuB;IAChE,MAAM,MAAM,GAAG,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC;IACrD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,yBAAiB,EAAE,CAAC;QACvC,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,wBAAwB,yBAAiB,GAAG,CAAC,CAAC;IAC3F,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC/B,kDAAkD;QAClD,IAAI,IAAI,GAAG,EAAE,IAAI,IAAI,GAAG,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,oCAAoC,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IACD,IAAI,GAAG,KAAK,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,mCAAmC,CAAC,CAAC;IAClF,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,GAAW,EAAE,IAAuB;IAC/D,SAAS,CAAC,GAAG,CAAC,CAAC;IACf,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;YACxD,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,gCAAgC,CAAC,CAAC;QAC/E,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,EAAE,GAAG,oBAAoB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IACjE,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,yBAAiB,EAAE,CAAC;QACzD,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,eAAe,yBAAiB,OAAO,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACpB,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,GAAG,IAAI,sBAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AASD;;;GAGG;AACH,SAAgB,YAAY,CAAC,KAAa;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,yBAAiB,EAAE,CAAC;QAC3D,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,mBAAmB,yBAAiB,KAAK,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,KAAK,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;IAC/C,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,SAAS,GAAG,CAAC,IAAI,SAAS,GAAG,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;QACvD,sCAAsC;QACtC,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,qCAAqC,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,IAAI,GAAG,EAAE,IAAI,IAAI,GAAG,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,oCAAoC,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IACD,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IAClD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,oBAAoB,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpF,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAClE,IAAI,OAAO,KAAK,YAAY,EAAE,CAAC;QAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,CAAC;IACD,IAAI,OAAO,KAAK,aAAa,EAAE,CAAC;QAC9B,8CAA8C;QAC9C,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,yCAAyC,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,WAAW,CAAC,IAAoC,EAAE,IAAY,EAAE,EAAU,EAAE,GAAY;IACtG,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,qBAAqB,IAAI,SAAS,CAAC,CAAC;QACjF,CAAC;QACD,WAAW,GAAG,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,cAAc,CAAC;QAC/D,IAAI,IAAI,IAAI,CAAC;QACb,OAAO,IAAI,IAAI,EAAE,EAAE,CAAC;YAClB,IAAI,IAAI,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IACD,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,IAAI,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;IAClE,CAAC;SAAM,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,GAAW,EAAE,OAAmB;IAClE,IAAI,CAAC,CAAC,OAAO,YAAY,UAAU,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,yBAAyB,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,YAAY,CAAC,GAAG,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,KAAa,EAAE,WAAoB;IACrE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,WAAW,KAAK,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC;YAC9C,MAAM,IAAI,qBAAY,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,UAAU,WAAW,OAAO,GAAG,GAAG,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IAC7C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * 字节与编码工具 —— 全部同构(Node 与浏览器跑同一份),不碰任何 Node 内建模块。
3
+ *
4
+ * 为什么自己写 base64 而不用 `btoa` / `Buffer`:
5
+ * - `Buffer` 是 Node 专有(同构守卫会拦,浏览器里也不存在)
6
+ * - `btoa` / `atob` 在 Node 里从 16 起才有,且只吃"二进制字符串",
7
+ * 一旦有人不小心传了非 Latin-1 字符就会静默出错(`btoa` 抛 InvalidCharacterError,
8
+ * 但更常见的是上游先做了 `String.fromCharCode` 而丢高位)
9
+ *
10
+ * 密文 blob 的字段(salt / iv / ciphertext / tag)都用 base64 而不是 hex:
11
+ * 体积小 25%,且与 protobuf JSON 的 `bytes` 惯例一致(入口文档 §8.1 那条坑就是
12
+ * "hex 塞进 `bytes` 字段 = 链上收到错字节还不报错")。
13
+ */
14
+ /** UTF-8 编码(`TextEncoder` 在 Node 11+/所有浏览器里都在全局) */
15
+ export declare function utf8ToBytes(text: string): Uint8Array;
16
+ /** UTF-8 解码;遇到非法字节序列时用替换字符(不抛)—— 只用于展示,不用于比对 */
17
+ export declare function bytesToUtf8(bytes: Uint8Array): string;
18
+ /** 小写 hex(`@noble/hashes/utils` 的同名实现,转出去方便调用方少装一个依赖) */
19
+ export declare function bytesToHex(bytes: Uint8Array): string;
20
+ /** hex → 字节;奇数长度 / 非法字符抛错(不做静默截断) */
21
+ export declare function hexToBytes(hex: string): Uint8Array;
22
+ /** 拼接若干字节数组(返回新数组,不改入参) */
23
+ export declare function concatBytes(...parts: readonly Uint8Array[]): Uint8Array;
24
+ /**
25
+ * 定时安全比较(逐字节 XOR 累积,不短路)。
26
+ *
27
+ * 用途:比对 tag / hash 这类**公开但需要防时序侧信道**的值。真正的认证判定
28
+ * 由 AES-GCM 在 WebCrypto 内部完成(它本身是常量时间的),本函数是给上层
29
+ * 做一致性检查时用的。
30
+ */
31
+ export declare function equalBytes(a: Uint8Array, b: Uint8Array): boolean;
32
+ /** 长度为 n 的全零数组 */
33
+ export declare function zeroBytes(length: number): Uint8Array;
34
+ /**
35
+ * 标准 base64(带 `=` 填充);空数组编码为 `''`。
36
+ *
37
+ * 用 `charAt` 而不是 `[i]`:索引已被 `& 0x3f` 掩到位域内,`charAt` 的返回类型是
38
+ * `string`(不是 `string | undefined`),省掉一串没意义的断言。
39
+ */
40
+ export declare function base64Encode(bytes: Uint8Array): string;
41
+ /**
42
+ * 标准 base64 解码。接受有填充与无填充两种写法;出现字母表外的字符、
43
+ * 或填充位不为零(非规范编码)时抛 `INVALID_ARGUMENT` —— 沉默地容忍畸形输入
44
+ * 会让"密文被改"变成"解出另一段字节",这类宽容在密钥库里是危险的。
45
+ */
46
+ export declare function base64Decode(text: string): Uint8Array;
47
+ /**
48
+ * 尽力清零:把**我们自己持有的** `Uint8Array` 填 0。
49
+ *
50
+ * ## 能做到什么、做不到什么(不夸大)
51
+ *
52
+ * ✅ 能:让这些数组对象里当前的内容变成 0 —— 对"用完就清"的密钥材料缓冲区有效。
53
+ * ❌ 不能:
54
+ * - **JS 字符串不可清零**(口令、助记词都是不可变字符串,只能等 GC;同一段明文
55
+ * 字符串在 V8 里还可能被内部化为共享常量)
56
+ * - 引擎/运行时的**内部副本不可达**:WASM 线性内存里 Argon2id 的输入缓冲、
57
+ * WebCrypto 内部持有的 key 副本、V8 的 rope/cons 字符串拼接中间态 —— 我们
58
+ * 拿不到指针,清不了
59
+ * - 数组一旦被 GC 移动过(压缩式 GC),旧地址上的残留数据也不由我们控制
60
+ * - 调用方如果自己 `slice()` / 展开 / 转 string 了,那些副本同样不在本函数射程内
61
+ *
62
+ * 所以这条 API 的定位是**降低窗口**而不是**保证抹除**。真正的防线是:
63
+ * 短生命周期(用完即丢)+ 不把明文写进任何持久化位置(本包不提供任何把明文
64
+ * 写 localStorage/sessionStorage 的路径)+ 不引第三方脚本(SDK 方案 §3.3.3 第 2 条)。
65
+ */
66
+ export declare function wipe(...buffers: readonly (Uint8Array | null | undefined)[]): void;
67
+ /**
68
+ * 用随机字节覆写后再清零(比单纯 `fill(0)` 少一点"编译器把清零优化掉"的顾虑,
69
+ * 虽然 JS 里不存在这种优化;真正的价值是让**曾经的内容**不再完整残留在堆上)。
70
+ * 需要随机源可用,不可用时退化为 `fill(0)`。
71
+ */
72
+ export declare function wipeRandom(randomBytes: (length: number) => Uint8Array, ...buffers: readonly (Uint8Array | null | undefined)[]): void;
73
+ /** 不可信 base64 字段的长度要求(三者可任意组合;都不给则只校验"是合法 base64") */
74
+ export interface BlobFieldLengthRule {
75
+ exact?: number;
76
+ min?: number;
77
+ max?: number;
78
+ }
79
+ /**
80
+ * 解一个**不可信来源**(磁盘 / IndexedDB / 网络)的 base64 字段。
81
+ *
82
+ * 与 `base64Decode` 的区别只在错误码:`base64Decode` 把"输入不合法"当**调用方
83
+ * 编程错误**抛 `INVALID_ARGUMENT`,而密文里的字段不是我们写的 —— 它不合法
84
+ * 属于"对方给的数据有问题",要抛 `INVALID_BLOB`。这条区分让调用方能一眼看出
85
+ * "是我传错了参数"还是"这份数据被改坏了"。
86
+ */
87
+ export declare function decodeBlobField(value: unknown, field: string, rule?: BlobFieldLengthRule): Uint8Array;
88
+ //# sourceMappingURL=bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,oDAAoD;AACpD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEpD;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAErD;AAED,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED,qCAAqC;AACrC,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAKlD;AAED,2BAA2B;AAC3B,wBAAgB,WAAW,CAAC,GAAG,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,UAAU,CASvE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAOhE;AAED,kBAAkB;AAClB,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAKpD;AAWD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAYtD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CA0BrD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,IAAI,CAAC,GAAG,OAAO,EAAE,SAAS,CAAC,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAIjF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,UAAU,EAC3C,GAAG,OAAO,EAAE,SAAS,CAAC,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GACrD,IAAI,CAUN;AAED,sDAAsD;AACtD,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,mBAAwB,GAC7B,UAAU,CAoBZ"}
package/dist/bytes.js ADDED
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ /**
3
+ * 字节与编码工具 —— 全部同构(Node 与浏览器跑同一份),不碰任何 Node 内建模块。
4
+ *
5
+ * 为什么自己写 base64 而不用 `btoa` / `Buffer`:
6
+ * - `Buffer` 是 Node 专有(同构守卫会拦,浏览器里也不存在)
7
+ * - `btoa` / `atob` 在 Node 里从 16 起才有,且只吃"二进制字符串",
8
+ * 一旦有人不小心传了非 Latin-1 字符就会静默出错(`btoa` 抛 InvalidCharacterError,
9
+ * 但更常见的是上游先做了 `String.fromCharCode` 而丢高位)
10
+ *
11
+ * 密文 blob 的字段(salt / iv / ciphertext / tag)都用 base64 而不是 hex:
12
+ * 体积小 25%,且与 protobuf JSON 的 `bytes` 惯例一致(入口文档 §8.1 那条坑就是
13
+ * "hex 塞进 `bytes` 字段 = 链上收到错字节还不报错")。
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.utf8ToBytes = utf8ToBytes;
17
+ exports.bytesToUtf8 = bytesToUtf8;
18
+ exports.bytesToHex = bytesToHex;
19
+ exports.hexToBytes = hexToBytes;
20
+ exports.concatBytes = concatBytes;
21
+ exports.equalBytes = equalBytes;
22
+ exports.zeroBytes = zeroBytes;
23
+ exports.base64Encode = base64Encode;
24
+ exports.base64Decode = base64Decode;
25
+ exports.wipe = wipe;
26
+ exports.wipeRandom = wipeRandom;
27
+ exports.decodeBlobField = decodeBlobField;
28
+ const utils_1 = require("@noble/hashes/utils");
29
+ const errors_1 = require("./errors");
30
+ /** UTF-8 编码(`TextEncoder` 在 Node 11+/所有浏览器里都在全局) */
31
+ function utf8ToBytes(text) {
32
+ return new TextEncoder().encode(text);
33
+ }
34
+ /** UTF-8 解码;遇到非法字节序列时用替换字符(不抛)—— 只用于展示,不用于比对 */
35
+ function bytesToUtf8(bytes) {
36
+ return new TextDecoder().decode(bytes);
37
+ }
38
+ /** 小写 hex(`@noble/hashes/utils` 的同名实现,转出去方便调用方少装一个依赖) */
39
+ function bytesToHex(bytes) {
40
+ return (0, utils_1.bytesToHex)(bytes);
41
+ }
42
+ /** hex → 字节;奇数长度 / 非法字符抛错(不做静默截断) */
43
+ function hexToBytes(hex) {
44
+ if (typeof hex !== 'string' || hex.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex)) {
45
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'hex 字符串非法(需偶数长度且仅含 0-9a-f)');
46
+ }
47
+ return (0, utils_1.hexToBytes)(hex);
48
+ }
49
+ /** 拼接若干字节数组(返回新数组,不改入参) */
50
+ function concatBytes(...parts) {
51
+ const total = parts.reduce((sum, part) => sum + part.length, 0);
52
+ const out = new Uint8Array(total);
53
+ let offset = 0;
54
+ for (const part of parts) {
55
+ out.set(part, offset);
56
+ offset += part.length;
57
+ }
58
+ return out;
59
+ }
60
+ /**
61
+ * 定时安全比较(逐字节 XOR 累积,不短路)。
62
+ *
63
+ * 用途:比对 tag / hash 这类**公开但需要防时序侧信道**的值。真正的认证判定
64
+ * 由 AES-GCM 在 WebCrypto 内部完成(它本身是常量时间的),本函数是给上层
65
+ * 做一致性检查时用的。
66
+ */
67
+ function equalBytes(a, b) {
68
+ if (a.length !== b.length)
69
+ return false;
70
+ let diff = 0;
71
+ for (let i = 0; i < a.length; i++) {
72
+ diff |= (a[i] ?? 0) ^ (b[i] ?? 0);
73
+ }
74
+ return diff === 0;
75
+ }
76
+ /** 长度为 n 的全零数组 */
77
+ function zeroBytes(length) {
78
+ if (!Number.isInteger(length) || length < 0) {
79
+ throw new errors_1.AccountError('INVALID_ARGUMENT', '长度必须是非负整数');
80
+ }
81
+ return new Uint8Array(length);
82
+ }
83
+ const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
84
+ const BASE64_LOOKUP = (() => {
85
+ const table = {};
86
+ for (let i = 0; i < BASE64_ALPHABET.length; i++) {
87
+ table[BASE64_ALPHABET.charAt(i)] = i;
88
+ }
89
+ return table;
90
+ })();
91
+ /**
92
+ * 标准 base64(带 `=` 填充);空数组编码为 `''`。
93
+ *
94
+ * 用 `charAt` 而不是 `[i]`:索引已被 `& 0x3f` 掩到位域内,`charAt` 的返回类型是
95
+ * `string`(不是 `string | undefined`),省掉一串没意义的断言。
96
+ */
97
+ function base64Encode(bytes) {
98
+ let out = '';
99
+ for (let i = 0; i < bytes.length; i += 3) {
100
+ const b1 = bytes[i + 1];
101
+ const b2 = bytes[i + 2];
102
+ const triple = ((bytes[i] ?? 0) << 16) | ((b1 ?? 0) << 8) | (b2 ?? 0);
103
+ out += BASE64_ALPHABET.charAt((triple >> 18) & 0x3f);
104
+ out += BASE64_ALPHABET.charAt((triple >> 12) & 0x3f);
105
+ out += b1 === undefined ? '=' : BASE64_ALPHABET.charAt((triple >> 6) & 0x3f);
106
+ out += b2 === undefined ? '=' : BASE64_ALPHABET.charAt(triple & 0x3f);
107
+ }
108
+ return out;
109
+ }
110
+ /**
111
+ * 标准 base64 解码。接受有填充与无填充两种写法;出现字母表外的字符、
112
+ * 或填充位不为零(非规范编码)时抛 `INVALID_ARGUMENT` —— 沉默地容忍畸形输入
113
+ * 会让"密文被改"变成"解出另一段字节",这类宽容在密钥库里是危险的。
114
+ */
115
+ function base64Decode(text) {
116
+ if (typeof text !== 'string') {
117
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'base64 输入必须是字符串');
118
+ }
119
+ const stripped = text.endsWith('==') ? text.slice(0, -2) : text.endsWith('=') ? text.slice(0, -1) : text;
120
+ const out = new Uint8Array(Math.floor((stripped.length * 6) / 8));
121
+ let accumulator = 0;
122
+ let bits = 0;
123
+ let index = 0;
124
+ for (const char of stripped) {
125
+ const value = BASE64_LOOKUP[char];
126
+ if (value === undefined) {
127
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'base64 字符串含非法字符');
128
+ }
129
+ accumulator = (accumulator << 6) | value;
130
+ bits += 6;
131
+ if (bits >= 8) {
132
+ bits -= 8;
133
+ out[index++] = (accumulator >> bits) & 0xff;
134
+ }
135
+ }
136
+ // 剩余位必须全是 0(否则这不是一份规范编码),且余数不能是单字节的 1 位
137
+ if (bits >= 6 || (accumulator & ((1 << bits) - 1)) !== 0) {
138
+ throw new errors_1.AccountError('INVALID_ARGUMENT', 'base64 字符串长度或填充位非法');
139
+ }
140
+ return out;
141
+ }
142
+ /**
143
+ * 尽力清零:把**我们自己持有的** `Uint8Array` 填 0。
144
+ *
145
+ * ## 能做到什么、做不到什么(不夸大)
146
+ *
147
+ * ✅ 能:让这些数组对象里当前的内容变成 0 —— 对"用完就清"的密钥材料缓冲区有效。
148
+ * ❌ 不能:
149
+ * - **JS 字符串不可清零**(口令、助记词都是不可变字符串,只能等 GC;同一段明文
150
+ * 字符串在 V8 里还可能被内部化为共享常量)
151
+ * - 引擎/运行时的**内部副本不可达**:WASM 线性内存里 Argon2id 的输入缓冲、
152
+ * WebCrypto 内部持有的 key 副本、V8 的 rope/cons 字符串拼接中间态 —— 我们
153
+ * 拿不到指针,清不了
154
+ * - 数组一旦被 GC 移动过(压缩式 GC),旧地址上的残留数据也不由我们控制
155
+ * - 调用方如果自己 `slice()` / 展开 / 转 string 了,那些副本同样不在本函数射程内
156
+ *
157
+ * 所以这条 API 的定位是**降低窗口**而不是**保证抹除**。真正的防线是:
158
+ * 短生命周期(用完即丢)+ 不把明文写进任何持久化位置(本包不提供任何把明文
159
+ * 写 localStorage/sessionStorage 的路径)+ 不引第三方脚本(SDK 方案 §3.3.3 第 2 条)。
160
+ */
161
+ function wipe(...buffers) {
162
+ for (const buffer of buffers) {
163
+ if (buffer)
164
+ buffer.fill(0);
165
+ }
166
+ }
167
+ /**
168
+ * 用随机字节覆写后再清零(比单纯 `fill(0)` 少一点"编译器把清零优化掉"的顾虑,
169
+ * 虽然 JS 里不存在这种优化;真正的价值是让**曾经的内容**不再完整残留在堆上)。
170
+ * 需要随机源可用,不可用时退化为 `fill(0)`。
171
+ */
172
+ function wipeRandom(randomBytes, ...buffers) {
173
+ for (const buffer of buffers) {
174
+ if (!buffer)
175
+ continue;
176
+ try {
177
+ buffer.set(randomBytes(buffer.length));
178
+ }
179
+ catch {
180
+ // 随机源不可用不该让"清理"这件事失败
181
+ }
182
+ buffer.fill(0);
183
+ }
184
+ }
185
+ /**
186
+ * 解一个**不可信来源**(磁盘 / IndexedDB / 网络)的 base64 字段。
187
+ *
188
+ * 与 `base64Decode` 的区别只在错误码:`base64Decode` 把"输入不合法"当**调用方
189
+ * 编程错误**抛 `INVALID_ARGUMENT`,而密文里的字段不是我们写的 —— 它不合法
190
+ * 属于"对方给的数据有问题",要抛 `INVALID_BLOB`。这条区分让调用方能一眼看出
191
+ * "是我传错了参数"还是"这份数据被改坏了"。
192
+ */
193
+ function decodeBlobField(value, field, rule = {}) {
194
+ if (typeof value !== 'string') {
195
+ throw new errors_1.AccountError('INVALID_BLOB', `${field} 必须是 base64 字符串`);
196
+ }
197
+ let decoded;
198
+ try {
199
+ decoded = base64Decode(value);
200
+ }
201
+ catch {
202
+ throw new errors_1.AccountError('INVALID_BLOB', `${field} 不是合法的 base64`);
203
+ }
204
+ if (rule.exact !== undefined && decoded.length !== rule.exact) {
205
+ throw new errors_1.AccountError('INVALID_BLOB', `${field} 解码后必须是 ${rule.exact} 字节(实际 ${decoded.length})`);
206
+ }
207
+ if (rule.min !== undefined && decoded.length < rule.min) {
208
+ throw new errors_1.AccountError('INVALID_BLOB', `${field} 解码后至少 ${rule.min} 字节(实际 ${decoded.length})`);
209
+ }
210
+ if (rule.max !== undefined && decoded.length > rule.max) {
211
+ throw new errors_1.AccountError('INVALID_BLOB', `${field} 解码后至多 ${rule.max} 字节(实际 ${decoded.length})`);
212
+ }
213
+ return decoded;
214
+ }
215
+ //# sourceMappingURL=bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes.js","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"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"}