@invisi-labs/primitives 0.0.0-stage → 1.2.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.
@@ -0,0 +1,1113 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod3) => __copyProps(__defProp({}, "__esModule", { value: true }), mod3);
19
+
20
+ // src/credit/index.ts
21
+ var credit_exports = {};
22
+ __export(credit_exports, {
23
+ CREDIT_POLICY_FIELDS: () => CREDIT_POLICY_FIELDS,
24
+ CREDIT_USAGE_FIELDS: () => CREDIT_USAGE_FIELDS,
25
+ applyCreditDrawUsage: () => applyCreditDrawUsage,
26
+ computeCreditCommitment: () => computeCreditCommitment,
27
+ computeCreditNullifier: () => computeCreditNullifier,
28
+ computeCreditRecoveryPad: () => computeCreditRecoveryPad,
29
+ computeCreditSharedKeyHash: () => computeCreditSharedKeyHash,
30
+ creditPeriods: () => creditPeriods,
31
+ decryptCreditState: () => decryptCreditState,
32
+ deriveCreditState: () => deriveCreditState,
33
+ deriveCreditStateNonce: () => deriveCreditStateNonce,
34
+ deriveCreditUpdate: () => deriveCreditUpdate,
35
+ encryptCreditState: () => encryptCreditState,
36
+ normalizeCreditDeliveryState: () => normalizeCreditDeliveryState,
37
+ normalizeCreditPolicy: () => normalizeCreditPolicy,
38
+ normalizeCreditState: () => normalizeCreditState,
39
+ normalizeCreditUsage: () => normalizeCreditUsage,
40
+ recoverCreditState: () => recoverCreditState
41
+ });
42
+ module.exports = __toCommonJS(credit_exports);
43
+
44
+ // src/crypto/domains.ts
45
+ var D_CREDIT = 5n;
46
+ var D_CNULL = 6n;
47
+ var D_CREDIT_KEY_HASH = 7n;
48
+ var D_CREDIT_RECOVERY = 9n;
49
+ var D_CREDIT_STATE_NONCE = 10n;
50
+
51
+ // src/crypto/random.ts
52
+ var FIELD_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
53
+
54
+ // src/crypto/poseidon-constants.ts
55
+ var INTERNAL_DIAGONAL = [
56
+ 0x10dc6e9c006ea38b04b1e03b4bd9490c0d03f98929ca1d7fb56821fd19d3b6e7n,
57
+ 0x0c28145b6a44df3e0149b3d0a30b3bb599df9756d4dd9b84a86b38cfb45a740bn,
58
+ 0x00544b8338791518b2c7645a50392798b21f75bb60e3596170067d00141cac15n,
59
+ 0x222c01175718386f2e2e82eb122789e352e105a3b8fa852613bc534433ee428bn
60
+ ];
61
+ var ROUND_CONSTANTS = [
62
+ [
63
+ 0x19b849f69450b06848da1d39bd5e4a4302bb86744edc26238b0878e269ed23e5n,
64
+ 0x265ddfe127dd51bd7239347b758f0a1320eb2cc7450acc1dad47f80c8dcf34d6n,
65
+ 0x199750ec472f1809e0f66a545e1e51624108ac845015c2aa3dfc36bab497d8aan,
66
+ 0x157ff3fe65ac7208110f06a5f74302b14d743ea25067f0ffd032f787c7f1cdf8n
67
+ ],
68
+ [
69
+ 0x2e49c43c4569dd9c5fd35ac45fca33f10b15c590692f8beefe18f4896ac94902n,
70
+ 0x0e35fb89981890520d4aef2b6d6506c3cb2f0b6973c24fa82731345ffa2d1f1en,
71
+ 0x251ad47cb15c4f1105f109ae5e944f1ba9d9e7806d667ffec6fe723002e0b996n,
72
+ 0x13da07dc64d428369873e97160234641f8beb56fdd05e5f3563fa39d9c22df4en
73
+ ],
74
+ [
75
+ 0x0c009b84e650e6d23dc00c7dccef7483a553939689d350cd46e7b89055fd4738n,
76
+ 0x011f16b1c63a854f01992e3956f42d8b04eb650c6d535eb0203dec74befdca06n,
77
+ 0x0ed69e5e383a688f209d9a561daa79612f3f78d0467ad45485df07093f367549n,
78
+ 0x04dba94a7b0ce9e221acad41472b6bbe3aec507f5eb3d33f463672264c9f789bn
79
+ ],
80
+ [
81
+ 0x0a3f2637d840f3a16eb094271c9d237b6036757d4bb50bf7ce732ff1d4fa28e8n,
82
+ 0x259a666f129eea198f8a1c502fdb38fa39b1f075569564b6e54a485d1182323fn,
83
+ 0x28bf7459c9b2f4c6d8e7d06a4ee3a47f7745d4271038e5157a32fdf7ede0d6a1n,
84
+ 0x0a1ca941f057037526ea200f489be8d4c37c85bbcce6a2aeec91bd6941432447n
85
+ ],
86
+ [0x0c6f8f958be0e93053d7fd4fc54512855535ed1539f051dcb43a26fd926361cfn, 0x0n, 0x0n, 0x0n],
87
+ [0x123106a93cd17578d426e8128ac9d90aa9e8a00708e296e084dd57e69caaf811n, 0x0n, 0x0n, 0x0n],
88
+ [0x26e1ba52ad9285d97dd3ab52f8e840085e8fa83ff1e8f1877b074867cd2dee75n, 0x0n, 0x0n, 0x0n],
89
+ [0x1cb55cad7bd133de18a64c5c47b9c97cbe4d8b7bf9e095864471537e6a4ae2c5n, 0x0n, 0x0n, 0x0n],
90
+ [0x1dcd73e46acd8f8e0e2c7ce04bde7f6d2a53043d5060a41c7143f08e6e9055d0n, 0x0n, 0x0n, 0x0n],
91
+ [0x011003e32f6d9c66f5852f05474a4def0cda294a0eb4e9b9b12b9bb4512e5574n, 0x0n, 0x0n, 0x0n],
92
+ [0x2b1e809ac1d10ab29ad5f20d03a57dfebadfe5903f58bafed7c508dd2287ae8cn, 0x0n, 0x0n, 0x0n],
93
+ [0x2539de1785b735999fb4dac35ee17ed0ef995d05ab2fc5faeaa69ae87bcec0a5n, 0x0n, 0x0n, 0x0n],
94
+ [0x0c246c5a2ef8ee0126497f222b3e0a0ef4e1c3d41c86d46e43982cb11d77951dn, 0x0n, 0x0n, 0x0n],
95
+ [0x192089c4974f68e95408148f7c0632edbb09e6a6ad1a1c2f3f0305f5d03b527bn, 0x0n, 0x0n, 0x0n],
96
+ [0x1eae0ad8ab68b2f06a0ee36eeb0d0c058529097d91096b756d8fdc2fb5a60d85n, 0x0n, 0x0n, 0x0n],
97
+ [0x179190e5d0e22179e46f8282872abc88db6e2fdc0dee99e69768bd98c5d06bfbn, 0x0n, 0x0n, 0x0n],
98
+ [0x29bb9e2c9076732576e9a81c7ac4b83214528f7db00f31bf6cafe794a9b3cd1cn, 0x0n, 0x0n, 0x0n],
99
+ [0x225d394e42207599403efd0c2464a90d52652645882aac35b10e590e6e691e08n, 0x0n, 0x0n, 0x0n],
100
+ [0x064760623c25c8cf753d238055b444532be13557451c087de09efd454b23fd59n, 0x0n, 0x0n, 0x0n],
101
+ [0x10ba3a0e01df92e87f301c4b716d8a394d67f4bf42a75c10922910a78f6b5b87n, 0x0n, 0x0n, 0x0n],
102
+ [0x0e070bf53f8451b24f9c6e96b0c2a801cb511bc0c242eb9d361b77693f21471cn, 0x0n, 0x0n, 0x0n],
103
+ [0x1b94cd61b051b04dd39755ff93821a73ccd6cb11d2491d8aa7f921014de252fbn, 0x0n, 0x0n, 0x0n],
104
+ [0x1d7cb39bafb8c744e148787a2e70230f9d4e917d5713bb050487b5aa7d74070bn, 0x0n, 0x0n, 0x0n],
105
+ [0x2ec93189bd1ab4f69117d0fe980c80ff8785c2961829f701bb74ac1f303b17dbn, 0x0n, 0x0n, 0x0n],
106
+ [0x2db366bfdd36d277a692bb825b86275beac404a19ae07a9082ea46bd83517926n, 0x0n, 0x0n, 0x0n],
107
+ [0x062100eb485db06269655cf186a68532985275428450359adc99cec6960711b8n, 0x0n, 0x0n, 0x0n],
108
+ [0x0761d33c66614aaa570e7f1e8244ca1120243f92fa59e4f900c567bf41f5a59bn, 0x0n, 0x0n, 0x0n],
109
+ [0x20fc411a114d13992c2705aa034e3f315d78608a0f7de4ccf7a72e494855ad0dn, 0x0n, 0x0n, 0x0n],
110
+ [0x25b5c004a4bdfcb5add9ec4e9ab219ba102c67e8b3effb5fc3a30f317250bc5an, 0x0n, 0x0n, 0x0n],
111
+ [0x23b1822d278ed632a494e58f6df6f5ed038b186d8474155ad87e7dff62b37f4bn, 0x0n, 0x0n, 0x0n],
112
+ [0x22734b4c5c3f9493606c4ba9012499bf0f14d13bfcfcccaa16102a29cc2f69e0n, 0x0n, 0x0n, 0x0n],
113
+ [0x26c0c8fe09eb30b7e27a74dc33492347e5bdff409aa3610254413d3fad795ce5n, 0x0n, 0x0n, 0x0n],
114
+ [0x070dd0ccb6bd7bbae88eac03fa1fbb26196be3083a809829bbd626df348ccad9n, 0x0n, 0x0n, 0x0n],
115
+ [0x12b6595bdb329b6fb043ba78bb28c3bec2c0a6de46d8c5ad6067c4ebfd4250dan, 0x0n, 0x0n, 0x0n],
116
+ [0x248d97d7f76283d63bec30e7a5876c11c06fca9b275c671c5e33d95bb7e8d729n, 0x0n, 0x0n, 0x0n],
117
+ [0x1a306d439d463b0816fc6fd64cc939318b45eb759ddde4aa106d15d9bd9baaaan, 0x0n, 0x0n, 0x0n],
118
+ [0x28a8f8372e3c38daced7c00421cb4621f4f1b54ddc27821b0d62d3d6ec7c56cfn, 0x0n, 0x0n, 0x0n],
119
+ [0x0094975717f9a8a8bb35152f24d43294071ce320c829f388bc852183e1e2ce7en, 0x0n, 0x0n, 0x0n],
120
+ [0x04d5ee4c3aa78f7d80fde60d716480d3593f74d4f653ae83f4103246db2e8d65n, 0x0n, 0x0n, 0x0n],
121
+ [0x2a6cf5e9aa03d4336349ad6fb8ed2269c7bef54b8822cc76d08495c12efde187n, 0x0n, 0x0n, 0x0n],
122
+ [0x2304d31eaab960ba9274da43e19ddeb7f792180808fd6e43baae48d7efcba3f3n, 0x0n, 0x0n, 0x0n],
123
+ [0x03fd9ac865a4b2a6d5e7009785817249bff08a7e0726fcb4e1c11d39d199f0b0n, 0x0n, 0x0n, 0x0n],
124
+ [0x00b7258ded52bbda2248404d55ee5044798afc3a209193073f7954d4d63b0b64n, 0x0n, 0x0n, 0x0n],
125
+ [0x159f81ada0771799ec38fca2d4bf65ebb13d3a74f3298db36272c5ca65e92d9an, 0x0n, 0x0n, 0x0n],
126
+ [0x1ef90e67437fbc8550237a75bc28e3bb9000130ea25f0c5471e144cf4264431fn, 0x0n, 0x0n, 0x0n],
127
+ [0x1e65f838515e5ff0196b49aa41a2d2568df739bc176b08ec95a79ed82932e30dn, 0x0n, 0x0n, 0x0n],
128
+ [0x2b1b045def3a166cec6ce768d079ba74b18c844e570e1f826575c1068c94c33fn, 0x0n, 0x0n, 0x0n],
129
+ [0x0832e5753ceb0ff6402543b1109229c165dc2d73bef715e3f1c6e07c168bb173n, 0x0n, 0x0n, 0x0n],
130
+ [0x02f614e9cedfb3dc6b762ae0a37d41bab1b841c2e8b6451bc5a8e3c390b6ad16n, 0x0n, 0x0n, 0x0n],
131
+ [0x0e2427d38bd46a60dd640b8e362cad967370ebb777bedff40f6a0be27e7ed705n, 0x0n, 0x0n, 0x0n],
132
+ [0x0493630b7c670b6deb7c84d414e7ce79049f0ec098c3c7c50768bbe29214a53an, 0x0n, 0x0n, 0x0n],
133
+ [0x22ead100e8e482674decdab17066c5a26bb1515355d5461a3dc06cc85327cea9n, 0x0n, 0x0n, 0x0n],
134
+ [0x25b3e56e655b42cdaae2626ed2554d48583f1ae35626d04de5084e0b6d2a6f16n, 0x0n, 0x0n, 0x0n],
135
+ [0x1e32752ada8836ef5837a6cde8ff13dbb599c336349e4c584b4fdc0a0cf6f9d0n, 0x0n, 0x0n, 0x0n],
136
+ [0x2fa2a871c15a387cc50f68f6f3c3455b23c00995f05078f672a9864074d412e5n, 0x0n, 0x0n, 0x0n],
137
+ [0x2f569b8a9a4424c9278e1db7311e889f54ccbf10661bab7fcd18e7c7a7d83505n, 0x0n, 0x0n, 0x0n],
138
+ [0x044cb455110a8fdd531ade530234c518a7df93f7332ffd2144165374b246b43dn, 0x0n, 0x0n, 0x0n],
139
+ [0x227808de93906d5d420246157f2e42b191fe8c90adfe118178ddc723a5319025n, 0x0n, 0x0n, 0x0n],
140
+ [0x02fcca2934e046bc623adead873579865d03781ae090ad4a8579d2e7a6800355n, 0x0n, 0x0n, 0x0n],
141
+ [0x0ef915f0ac120b876abccceb344a1d36bad3f3c5ab91a8ddcbec2e060d8befacn, 0x0n, 0x0n, 0x0n],
142
+ [
143
+ 0x1797130f4b7a3e1777eb757bc6f287f6ab0fb85f6be63b09f3b16ef2b1405d38n,
144
+ 0x0a76225dc04170ae3306c85abab59e608c7f497c20156d4d36c668555decc6e5n,
145
+ 0x1fffb9ec1992d66ba1e77a7b93209af6f8fa76d48acb664796174b5326a31a5cn,
146
+ 0x25721c4fc15a3f2853b57c338fa538d85f8fbba6c6b9c6090611889b797b9c5fn
147
+ ],
148
+ [
149
+ 0x0c817fd42d5f7a41215e3d07ba197216adb4c3790705da95eb63b982bfcaf75an,
150
+ 0x13abe3f5239915d39f7e13c2c24970b6df8cf86ce00a22002bc15866e52b5a96n,
151
+ 0x2106feea546224ea12ef7f39987a46c85c1bc3dc29bdbd7a92cd60acb4d391cen,
152
+ 0x21ca859468a746b6aaa79474a37dab49f1ca5a28c748bc7157e1b3345bb0f959n
153
+ ],
154
+ [
155
+ 0x05ccd6255c1e6f0c5cf1f0df934194c62911d14d0321662a8f1a48999e34185bn,
156
+ 0x0f0e34a64b70a626e464d846674c4c8816c4fb267fe44fe6ea28678cb09490a4n,
157
+ 0x0558531a4e25470c6157794ca36d0e9647dbfcfe350d64838f5b1a8a2de0d4bfn,
158
+ 0x09d3dca9173ed2faceea125157683d18924cadad3f655a60b72f5864961f1455n
159
+ ],
160
+ [
161
+ 0x0328cbd54e8c0913493f866ed03d218bf23f92d68aaec48617d4c722e5bd4335n,
162
+ 0x2bf07216e2aff0a223a487b1a7094e07e79e7bcc9798c648ee3347dd5329d34bn,
163
+ 0x1daf345a58006b736499c583cb76c316d6f78ed6a6dffc82111e11a63fe412dfn,
164
+ 0x176563472456aaa746b694c60e1823611ef39039b2edc7ff391e6f2293d2c404n
165
+ ]
166
+ ];
167
+
168
+ // src/crypto/poseidon.ts
169
+ var mod = (n) => n % FIELD_MODULUS;
170
+ var fifth = (n) => {
171
+ const x = mod(n), x2 = mod(x * x);
172
+ return mod(x * x2 * x2);
173
+ };
174
+ function external(s) {
175
+ const t0 = s[0] + s[1], t1 = s[2] + s[3], t2 = 2n * s[1] + t1, t3 = 2n * s[3] + t0;
176
+ const t4 = 4n * t1 + t3, t5 = 4n * t0 + t2;
177
+ s[0] = mod(t3 + t5);
178
+ s[1] = mod(t5);
179
+ s[2] = mod(t2 + t4);
180
+ s[3] = mod(t4);
181
+ }
182
+ function permute(s) {
183
+ external(s);
184
+ for (let r = 0; r < 64; r++) {
185
+ const full = r < 4 || r >= 60, rc = ROUND_CONSTANTS[r];
186
+ if (full) {
187
+ for (let i = 0; i < 4; i++) s[i] = fifth(s[i] + rc[i]);
188
+ external(s);
189
+ } else {
190
+ s[0] = fifth(s[0] + rc[0]);
191
+ const sum = s.reduce((a, b) => a + b, 0n);
192
+ for (let i = 0; i < 4; i++) s[i] = mod(s[i] * INTERNAL_DIAGONAL[i] + sum);
193
+ }
194
+ }
195
+ }
196
+ async function poseidonHash(inputs) {
197
+ for (let i = 0; i < inputs.length; i++)
198
+ if (inputs[i] < 0n || inputs[i] >= FIELD_MODULUS)
199
+ throw new RangeError(
200
+ `poseidonHash: input[${i}] out of BN254 field range [0, FIELD_MODULUS): ${inputs[i]}`
201
+ );
202
+ const state = [0n, 0n, 0n, BigInt(inputs.length) << 64n];
203
+ let used = 0;
204
+ for (const input of inputs) {
205
+ if (used === 3) {
206
+ permute(state);
207
+ used = 0;
208
+ }
209
+ state[used] = mod(state[used] + input);
210
+ used++;
211
+ }
212
+ permute(state);
213
+ return `0x${state[0].toString(16).padStart(64, "0")}`;
214
+ }
215
+
216
+ // src/notes/noteContext.ts
217
+ function assertNoteContext(note, context) {
218
+ if (note.chainId !== context.chainId || note.protocolAddress !== context.protocolAddress) {
219
+ throw new Error("note context mismatch");
220
+ }
221
+ }
222
+
223
+ // src/credit/state.ts
224
+ var CREDIT_POLICY_FIELDS = ["singleLimit", "dailyLimit", "monthlyLimit"];
225
+ var CREDIT_USAGE_FIELDS = [
226
+ "lastDay",
227
+ "dailySpent",
228
+ "lastMonth",
229
+ "monthlySpent",
230
+ "totalSpent"
231
+ ];
232
+ function normalizeCreditPolicy(value = {}) {
233
+ return Object.fromEntries(
234
+ CREDIT_POLICY_FIELDS.map((key) => {
235
+ const n = value[key] ?? 0n;
236
+ uint(n, 126, key);
237
+ return [key, n];
238
+ })
239
+ );
240
+ }
241
+ function normalizeCreditUsage(value = {}) {
242
+ const usage = Object.fromEntries(
243
+ CREDIT_USAGE_FIELDS.map((key) => {
244
+ const n = value[key] ?? 0n;
245
+ uint(n, key === "lastDay" || key === "lastMonth" ? 64 : 128, key);
246
+ return [key, n];
247
+ })
248
+ );
249
+ for (const [period, spent] of [
250
+ ["lastDay", "dailySpent"],
251
+ ["lastMonth", "monthlySpent"]
252
+ ])
253
+ if (usage[period] === 0n && usage[spent] !== 0n) throw Error("noncanonical Credit usage");
254
+ return usage;
255
+ }
256
+ function balance(value) {
257
+ uint(value.availableCredit, 128, "availableCredit");
258
+ if (typeof value.unlimited !== "boolean") throw TypeError("unlimited must be boolean");
259
+ if (value.unlimited && value.availableCredit !== 0n)
260
+ throw Error("unlimited Credit must have zero available credit");
261
+ return { availableCredit: value.availableCredit, unlimited: value.unlimited };
262
+ }
263
+ function creditPeriods(timestamp) {
264
+ if (typeof timestamp !== "bigint") throw new TypeError("Credit timestamp required");
265
+ uint(timestamp, 64, "timestamp");
266
+ const days = timestamp / 86400n, z = days + 719468n, era = z / 146097n, doe = z - era * 146097n;
267
+ const yoe = (doe - doe / 1460n + doe / 36524n - doe / 146096n) / 365n;
268
+ let year = yoe + era * 400n;
269
+ const doy = doe - (365n * yoe + yoe / 4n - yoe / 100n), mp = (5n * doy + 2n) / 153n;
270
+ const month = mp + (mp < 10n ? 3n : -9n);
271
+ if (month <= 2n) year++;
272
+ return { currentDay: days + 1n, currentMonth: (year - 1970n) * 12n + month };
273
+ }
274
+ function applyCreditDrawUsage(note, amount, timestamp) {
275
+ const policy = {
276
+ ...normalizeCreditPolicy(note),
277
+ ...normalizeCreditUsage(note),
278
+ ...balance(note)
279
+ }, periods = creditPeriods(timestamp);
280
+ uint(amount, 126, "draw amount");
281
+ if (amount === 0n) throw new Error("draw amount must be positive");
282
+ if (policy.singleLimit !== 0n && amount > policy.singleLimit)
283
+ throw new Error("single limit exceeded");
284
+ for (const [limit, last, spent, current] of [
285
+ ["dailyLimit", "lastDay", "dailySpent", "currentDay"],
286
+ ["monthlyLimit", "lastMonth", "monthlySpent", "currentMonth"]
287
+ ]) {
288
+ const period = periods[current];
289
+ if (period < policy[last]) throw new Error("Credit period rollback");
290
+ policy[spent] = (period === policy[last] ? policy[spent] : 0n) + amount;
291
+ uint(policy[spent], 128, spent);
292
+ policy[last] = period;
293
+ if (policy[limit] !== 0n && policy[spent] > policy[limit])
294
+ throw new Error(`${limit} exceeded`);
295
+ }
296
+ policy.totalSpent += amount;
297
+ uint(policy.totalSpent, 128, "totalSpent");
298
+ if (!policy.unlimited) {
299
+ if (amount > policy.availableCredit) throw Error("available credit exceeded");
300
+ policy.availableCredit -= amount;
301
+ }
302
+ return policy;
303
+ }
304
+ async function computeCreditSharedKeyHash(creditSharedKey) {
305
+ if (creditSharedKey <= 0n || creditSharedKey >= FIELD_MODULUS)
306
+ throw new RangeError("invalid Credit shared key");
307
+ return poseidonHash([D_CREDIT_KEY_HASH, creditSharedKey]);
308
+ }
309
+ function normalizeCreditState(state) {
310
+ const allowed = [
311
+ "chainId",
312
+ "protocolAddress",
313
+ "tokenAddress",
314
+ "spenderWalletIdentity",
315
+ "ownerWalletIdentity",
316
+ "revocationShard",
317
+ "revocationSlot",
318
+ "nonce",
319
+ "expiry",
320
+ "creditSharedKey",
321
+ ...CREDIT_POLICY_FIELDS,
322
+ ...CREDIT_USAGE_FIELDS,
323
+ "availableCredit",
324
+ "unlimited",
325
+ "payload"
326
+ ];
327
+ if (!state || typeof state !== "object" || Object.keys(state).some((k) => !allowed.includes(k)))
328
+ throw Error("Unsupported Credit fields");
329
+ for (const [name, bits] of [
330
+ ["chainId", 64],
331
+ ["protocolAddress", 160],
332
+ ["tokenAddress", 160],
333
+ ["revocationShard", 64],
334
+ ["revocationSlot", 16],
335
+ ["expiry", 64]
336
+ ])
337
+ uint(state[name], bits, name);
338
+ for (const id of [state.spenderWalletIdentity, state.ownerWalletIdentity])
339
+ if (!/^0x[0-9a-fA-F]{40}$/.test(id) || BigInt(id) === 0n)
340
+ throw Error("invalid Credit identity");
341
+ if (!state.protocolAddress || !state.tokenAddress || !state.revocationShard || !state.expiry)
342
+ throw Error("Credit deployment, token, shard and expiry must be positive");
343
+ field(state.nonce, "nonce");
344
+ field(state.creditSharedKey, "creditSharedKey");
345
+ if (!state.creditSharedKey) throw Error("Credit shared key must be positive");
346
+ if (state.payload !== void 0 && !(state.payload instanceof Uint8Array))
347
+ throw TypeError("payload must be Uint8Array");
348
+ return {
349
+ ...state,
350
+ ...normalizeCreditPolicy(state),
351
+ ...normalizeCreditUsage(state),
352
+ ...balance(state),
353
+ ...state.payload !== void 0 ? { payload: Uint8Array.from(state.payload) } : {}
354
+ };
355
+ }
356
+ async function computeCreditCommitment(state, keyHash) {
357
+ if (keyHash === void 0) state = normalizeCreditState(state);
358
+ for (const [name, bits] of [
359
+ ["chainId", 64],
360
+ ["protocolAddress", 160],
361
+ ["tokenAddress", 160],
362
+ ["revocationShard", 64],
363
+ ["revocationSlot", 16],
364
+ ["expiry", 64]
365
+ ])
366
+ uint(state[name], bits, name);
367
+ for (const identity of [state.spenderWalletIdentity, state.ownerWalletIdentity])
368
+ if (!/^0x[0-9a-fA-F]{40}$/.test(identity) || BigInt(identity) === 0n)
369
+ throw new Error("invalid Credit identity");
370
+ if (state.revocationShard === 0n || state.expiry === 0n)
371
+ throw new Error("Credit shard and expiry must be positive");
372
+ field(state.nonce, "nonce");
373
+ const hash = keyHash ?? await computeCreditSharedKeyHash(state.creditSharedKey);
374
+ field(BigInt(hash), "Credit shared key hash");
375
+ return poseidonHash([
376
+ D_CREDIT,
377
+ state.chainId,
378
+ state.protocolAddress,
379
+ BigInt(state.spenderWalletIdentity),
380
+ BigInt(state.ownerWalletIdentity),
381
+ state.tokenAddress,
382
+ state.revocationShard,
383
+ state.revocationSlot,
384
+ state.nonce,
385
+ state.expiry,
386
+ BigInt(hash),
387
+ ...CREDIT_POLICY_FIELDS.map((k) => normalizeCreditPolicy(state)[k]),
388
+ balance(state).availableCredit,
389
+ state.unlimited ? 1n : 0n,
390
+ ...CREDIT_USAGE_FIELDS.map((k) => normalizeCreditUsage(state)[k])
391
+ ]);
392
+ }
393
+ async function computeCreditNullifier(chainId, creditSharedKey, creditCommitment2) {
394
+ uint(chainId, 64, "chainId");
395
+ if (creditSharedKey <= 0n || creditSharedKey >= FIELD_MODULUS)
396
+ throw new RangeError("invalid Credit shared key");
397
+ if (!/^0x[0-9a-fA-F]{64}$/.test(creditCommitment2))
398
+ throw new Error("invalid Credit commitment encoding");
399
+ return poseidonHash([D_CNULL, chainId, creditSharedKey, BigInt(creditCommitment2)]);
400
+ }
401
+ async function deriveCreditStateNonce(chainId, protocolAddress, tokenAddress, creditNullifier, creditSharedKey) {
402
+ return BigInt(
403
+ await poseidonHash([
404
+ D_CREDIT_STATE_NONCE,
405
+ chainId,
406
+ protocolAddress,
407
+ tokenAddress,
408
+ creditNullifier,
409
+ creditSharedKey
410
+ ])
411
+ );
412
+ }
413
+ async function computeCreditRecoveryPad(chainId, protocolAddress, tokenAddress, creditNullifier, creditSharedKey) {
414
+ return BigInt(
415
+ await poseidonHash([
416
+ D_CREDIT_RECOVERY,
417
+ chainId,
418
+ protocolAddress,
419
+ tokenAddress,
420
+ creditNullifier,
421
+ creditSharedKey
422
+ ])
423
+ );
424
+ }
425
+ function uint(value, bits, name) {
426
+ if (typeof value !== "bigint" || value < 0n || value >= 1n << BigInt(bits))
427
+ throw new RangeError(`${name} out of uint${bits} range`);
428
+ }
429
+ function field(value, name) {
430
+ if (typeof value !== "bigint" || value < 0n || value >= FIELD_MODULUS)
431
+ throw new RangeError(`${name} out of BN254 field range`);
432
+ }
433
+ async function recoverCreditState(context, previous, recovery) {
434
+ assertNoteContext(previous, context);
435
+ const nullifier = await computeCreditNullifier(
436
+ context.chainId,
437
+ previous.creditSharedKey,
438
+ await computeCreditCommitment(previous)
439
+ );
440
+ if (nullifier.toLowerCase() !== recovery.creditNullifier.toLowerCase())
441
+ throw new Error("previous Credit nullifier mismatch");
442
+ field(recovery.recoveryAmount, "recoveryAmount");
443
+ const args = [
444
+ context.chainId,
445
+ context.protocolAddress,
446
+ previous.tokenAddress,
447
+ BigInt(nullifier),
448
+ previous.creditSharedKey
449
+ ];
450
+ const nonce = await deriveCreditStateNonce(...args), mask = await computeCreditRecoveryPad(...args);
451
+ const debit = (recovery.recoveryAmount - mask + FIELD_MODULUS) % FIELD_MODULUS;
452
+ uint(debit, 126, "recovered debit");
453
+ if (!debit) throw new Error("invalid recovered debit");
454
+ if (nonce === previous.nonce) throw new Error("state nonce must change");
455
+ const { payload, ...financial } = previous;
456
+ const state = {
457
+ ...financial,
458
+ ...applyCreditDrawUsage(previous, debit, recovery.timestamp),
459
+ nonce
460
+ };
461
+ if (await computeCreditCommitment(state) !== recovery.stateCommitment)
462
+ throw new Error("recovered Credit commitment mismatch");
463
+ return state;
464
+ }
465
+ async function deriveCreditState(previous, debit, timestamp) {
466
+ const nullifier = await computeCreditNullifier(
467
+ previous.chainId,
468
+ previous.creditSharedKey,
469
+ await computeCreditCommitment(previous)
470
+ );
471
+ const args = [
472
+ previous.chainId,
473
+ previous.protocolAddress,
474
+ previous.tokenAddress,
475
+ BigInt(nullifier),
476
+ previous.creditSharedKey
477
+ ];
478
+ const nonce = await deriveCreditStateNonce(...args), mask = await computeCreditRecoveryPad(...args);
479
+ if (nonce === previous.nonce) throw Error("state nonce must change");
480
+ const state = { ...previous, ...applyCreditDrawUsage(previous, debit, timestamp), nonce };
481
+ return {
482
+ state,
483
+ stateCommitment: await computeCreditCommitment(state),
484
+ nullifier,
485
+ recoveryAmount: (debit + mask) % FIELD_MODULUS
486
+ };
487
+ }
488
+ async function deriveCreditUpdate(previous, changes, deadline) {
489
+ for (const key of Object.keys(changes))
490
+ if (![
491
+ ...CREDIT_POLICY_FIELDS,
492
+ "expiry",
493
+ "unlimited",
494
+ "increaseAvailableCredit",
495
+ "decreaseAvailableCredit"
496
+ ].includes(key))
497
+ throw Error("unsupported Credit update field");
498
+ const old = normalizeCreditState(previous), increase = changes.increaseAvailableCredit === void 0 ? 0n : changes.increaseAvailableCredit, decrease = changes.decreaseAvailableCredit === void 0 ? 0n : changes.decreaseAvailableCredit;
499
+ uint(increase, 128, "increaseAvailableCredit");
500
+ uint(decrease, 128, "decreaseAvailableCredit");
501
+ if (increase !== 0n && decrease !== 0n)
502
+ throw Error("Credit increase and decrease are mutually exclusive");
503
+ const unlimited = changes.unlimited === void 0 ? old.unlimited : changes.unlimited;
504
+ if (typeof unlimited !== "boolean") throw TypeError("unlimited must be boolean");
505
+ let availableCredit = 0n;
506
+ if (unlimited) {
507
+ if (increase !== 0n || decrease !== 0n)
508
+ throw Error("unlimited update cannot adjust available credit");
509
+ } else {
510
+ if (decrease > old.availableCredit)
511
+ throw Error("available credit decrease exceeds balance");
512
+ availableCredit = old.availableCredit + increase - decrease;
513
+ uint(availableCredit, 128, "availableCredit");
514
+ }
515
+ uint(deadline, 64, "deadline");
516
+ const next = {
517
+ ...old,
518
+ ...normalizeCreditPolicy({ ...old, ...changes }),
519
+ expiry: changes.expiry ?? old.expiry,
520
+ availableCredit,
521
+ unlimited
522
+ };
523
+ if (previous.expiry < deadline || next.expiry < deadline)
524
+ throw Error("expiry before request deadline");
525
+ const nullifier = await computeCreditNullifier(
526
+ previous.chainId,
527
+ previous.creditSharedKey,
528
+ await computeCreditCommitment(previous)
529
+ );
530
+ const nonce = await deriveCreditStateNonce(
531
+ previous.chainId,
532
+ previous.protocolAddress,
533
+ previous.tokenAddress,
534
+ BigInt(nullifier),
535
+ previous.creditSharedKey
536
+ );
537
+ if (nonce === previous.nonce) throw Error("state nonce must change");
538
+ const state = { ...next, nonce };
539
+ return { state, nullifier, stateCommitment: await computeCreditCommitment(state) };
540
+ }
541
+
542
+ // src/delivery/delivery-codec.ts
543
+ var import_ethers = require("ethers");
544
+
545
+ // src/delivery/note-payload.ts
546
+ var import_secp256k1 = require("@noble/curves/secp256k1");
547
+
548
+ // src/fmd/fmd.ts
549
+ var import_blake2b2 = require("@noble/hashes/blake2b");
550
+ var import_utils = require("@noble/hashes/utils");
551
+
552
+ // src/fmd/decaf377.ts
553
+ var import_edwards = require("@noble/curves/abstract/edwards");
554
+ var import_modular = require("@noble/curves/abstract/modular");
555
+ var import_blake2b = require("@noble/hashes/blake2b");
556
+ var FQ = 8444461749428370424248824938781546531375899335154063827935233455917409239041n;
557
+ var FR = 2111115437357092606062206234695386632838870926408408195193685246394721360383n;
558
+ var field2 = (0, import_modular.Field)(FQ, 253, true);
559
+ var f = (n) => (0, import_modular.mod)(n, FQ);
560
+ function secureRandomBytes(length) {
561
+ const webCrypto = globalThis.crypto;
562
+ if (!webCrypto?.getRandomValues) throw new Error("WebCrypto secure randomness is unavailable");
563
+ return webCrypto.getRandomValues(new Uint8Array(length));
564
+ }
565
+ var curve = (0, import_edwards.twistedEdwards)({
566
+ a: FQ - 1n,
567
+ d: 3021n,
568
+ Fp: field2,
569
+ n: FR,
570
+ h: 4n,
571
+ Gx: 4959445789346820725352484487855828915252512307947624787834978378872129235627n,
572
+ Gy: 6060471950081851567114691557659790004756535011754163002297540472747064943288n,
573
+ hash: import_blake2b.blake2b,
574
+ randomBytes: (length = 32) => secureRandomBytes(length)
575
+ });
576
+ var generator = curve.ExtendedPoint.BASE;
577
+ function readLE(bytes2) {
578
+ let n = 0n;
579
+ for (let i = bytes2.length - 1; i >= 0; i--) n = n << 8n | BigInt(bytes2[i]);
580
+ return n;
581
+ }
582
+ function decodePoint(bytes2) {
583
+ if (!(bytes2 instanceof Uint8Array) || bytes2.length !== 32)
584
+ throw new Error("Invalid Decaf377 encoding length");
585
+ const s = readLE(bytes2);
586
+ if (s >= FQ || (s & 1n) !== 0n || bytes2[31] >> 5 !== 0)
587
+ throw new Error("Invalid Decaf377 encoding");
588
+ const ss = f(s * s);
589
+ const u1 = f(1n - ss);
590
+ const u2 = f(u1 * u1 - 4n * 3021n * ss);
591
+ const denominator = f(u2 * u1 * u1);
592
+ if (denominator === 0n) throw new Error("Invalid Decaf377 encoding");
593
+ let v;
594
+ try {
595
+ v = field2.sqrt(field2.inv(denominator));
596
+ } catch {
597
+ throw new Error("Invalid Decaf377 encoding");
598
+ }
599
+ const twoSU1 = f(2n * s * u1);
600
+ if ((f(twoSU1 * v) & 1n) !== 0n) v = f(-v);
601
+ const x = f(twoSU1 * v * v * u2);
602
+ const y = f((1n + ss) * v * u1);
603
+ return curve.ExtendedPoint.fromAffine({ x, y });
604
+ }
605
+ function isIdentity(point) {
606
+ return point.ex === 0n;
607
+ }
608
+
609
+ // src/fmd/fmd.ts
610
+ function requireBytes(value, length, name) {
611
+ if (!(value instanceof Uint8Array) || value.length !== length)
612
+ throw new TypeError(`${name} must be a ${length}-byte Uint8Array`);
613
+ }
614
+ function validateClueKey(clueKey) {
615
+ requireBytes(clueKey, 32, "Clue key");
616
+ if (isIdentity(decodePoint(clueKey))) throw new Error("Clue key must not be the identity");
617
+ }
618
+
619
+ // src/delivery/note-payload.ts
620
+ function concat(...parts) {
621
+ const out = new Uint8Array(parts.reduce((length, part) => length + part.length, 0));
622
+ let offset = 0;
623
+ for (const part of parts) {
624
+ out.set(part, offset);
625
+ offset += part.length;
626
+ }
627
+ return out;
628
+ }
629
+ function uint2(value, bits, name) {
630
+ if (value < 0n || value >= 1n << BigInt(bits))
631
+ throw new RangeError(`${name} out of uint${bits} range`);
632
+ }
633
+ function encode(value, length = 32) {
634
+ uint2(value, length * 8, "encoded value");
635
+ const out = new Uint8Array(length);
636
+ for (let i = length - 1; i >= 0; i--) {
637
+ out[i] = Number(value & 255n);
638
+ value >>= 8n;
639
+ }
640
+ return out;
641
+ }
642
+ function decode(value) {
643
+ return value.reduce((result, byte) => result << 8n | BigInt(byte), 0n);
644
+ }
645
+ function hexField(value) {
646
+ uint2(value, 160, "owner address");
647
+ return `0x${value.toString(16).padStart(40, "0")}`;
648
+ }
649
+ function receivingKeys(keys) {
650
+ if (!keys || !(keys.viewingPublicKey instanceof Uint8Array) || !(keys.clueKey instanceof Uint8Array))
651
+ throw new Error("receiving keys required");
652
+ const viewingPublicKey2 = Uint8Array.from(keys.viewingPublicKey), clueKey = Uint8Array.from(keys.clueKey);
653
+ if (viewingPublicKey2.length !== 33 || viewingPublicKey2[0] !== 2 && viewingPublicKey2[0] !== 3)
654
+ throw new Error("invalid compressed viewing public key");
655
+ import_secp256k1.secp256k1.ProjectivePoint.fromHex(viewingPublicKey2).assertValidity();
656
+ if (clueKey.length !== 32) throw new Error("invalid clue key length");
657
+ validateClueKey(clueKey);
658
+ return { viewingPublicKey: viewingPublicKey2, clueKey };
659
+ }
660
+ function normalizeCreditDeliveryState(state) {
661
+ if (!state || typeof state !== "object" || !state.note || typeof state.note !== "object")
662
+ throw new TypeError("complete Credit delivery state required");
663
+ const allowed = [
664
+ "chainId",
665
+ "protocolAddress",
666
+ "tokenAddress",
667
+ "spenderWalletIdentity",
668
+ "ownerWalletIdentity",
669
+ "revocationShard",
670
+ "revocationSlot",
671
+ "nonce",
672
+ "expiry",
673
+ "creditSharedKey",
674
+ "singleLimit",
675
+ "dailyLimit",
676
+ "monthlyLimit",
677
+ "availableCredit",
678
+ "unlimited",
679
+ "lastDay",
680
+ "dailySpent",
681
+ "lastMonth",
682
+ "monthlySpent",
683
+ "totalSpent",
684
+ "payload"
685
+ ];
686
+ if (Object.keys(state.note).some((k) => !allowed.includes(k)))
687
+ throw Error("Unsupported Credit fields");
688
+ const note = normalizeCreditState(structuredClone(state.note));
689
+ return {
690
+ note: {
691
+ ...note,
692
+ ...normalizeCreditPolicy(note)
693
+ },
694
+ ownerReceivingKeys: receivingKeys(state.ownerReceivingKeys),
695
+ spenderReceivingKeys: receivingKeys(state.spenderReceivingKeys)
696
+ };
697
+ }
698
+ function encodePayload(value) {
699
+ if (value !== void 0 && !(value instanceof Uint8Array))
700
+ throw new TypeError("payload must be Uint8Array");
701
+ const payload = value ?? new Uint8Array();
702
+ if (payload.length > 65535) throw new RangeError("payload length exceeds uint16");
703
+ return concat(encode(BigInt(payload.length), 2), payload);
704
+ }
705
+ function readPayload(plain, offset) {
706
+ if (plain.length < offset + 2) throw new Error("missing payload length");
707
+ const length = Number(decode(plain.slice(offset, offset + 2)));
708
+ if (plain.length !== offset + 2 + length) throw new Error("invalid payload length");
709
+ return Uint8Array.from(plain.subarray(offset + 2));
710
+ }
711
+ var fundsEnvelopeV1 = {
712
+ kind: "funds",
713
+ version: 1,
714
+ minimum: 160,
715
+ maximum: 4096,
716
+ encode(note) {
717
+ return concat(
718
+ encode(BigInt(note.ownerAddress)),
719
+ encode(note.amount, 16),
720
+ encode(note.nonce),
721
+ encodePayload(note.payload)
722
+ );
723
+ },
724
+ decode(plain, context) {
725
+ return {
726
+ chainId: context.chainId,
727
+ protocolAddress: context.protocolAddress,
728
+ tokenAddress: context.tokenAddress,
729
+ ownerAddress: hexField(decode(plain.slice(0, 32))),
730
+ amount: decode(plain.slice(32, 48)),
731
+ nonce: decode(plain.slice(48, 80)),
732
+ payload: readPayload(plain, 80)
733
+ };
734
+ }
735
+ };
736
+ var creditWireFields = [
737
+ ["spenderWalletIdentity", 32],
738
+ ["ownerWalletIdentity", 32],
739
+ ["revocationShard", 8],
740
+ ["revocationSlot", 2],
741
+ ["nonce", 32],
742
+ ["expiry", 8],
743
+ ["creditSharedKey", 32],
744
+ ["singleLimit", 16],
745
+ ["dailyLimit", 16],
746
+ ["monthlyLimit", 16],
747
+ ["availableCredit", 16],
748
+ ["unlimited", 1],
749
+ ["lastDay", 8],
750
+ ["dailySpent", 16],
751
+ ["lastMonth", 8],
752
+ ["monthlySpent", 16],
753
+ ["totalSpent", 16]
754
+ ];
755
+ var creditEnvelopeV2 = {
756
+ kind: "credit",
757
+ version: 2,
758
+ minimum: 485,
759
+ maximum: 4096,
760
+ encode(input) {
761
+ const state = normalizeCreditDeliveryState(input);
762
+ return concat(
763
+ ...creditWireFields.map(([k, size]) => encode(BigInt(state.note[k]), size)),
764
+ state.ownerReceivingKeys.viewingPublicKey,
765
+ state.ownerReceivingKeys.clueKey,
766
+ state.spenderReceivingKeys.viewingPublicKey,
767
+ state.spenderReceivingKeys.clueKey,
768
+ encodePayload(state.note.payload)
769
+ );
770
+ },
771
+ decode(plain, context) {
772
+ let offset = 0;
773
+ const note = {
774
+ chainId: context.chainId,
775
+ protocolAddress: context.protocolAddress,
776
+ tokenAddress: context.tokenAddress
777
+ };
778
+ for (const [k, size] of creditWireFields) {
779
+ const n = decode(plain.slice(offset, offset + size));
780
+ if (k === "unlimited" && n !== 0n && n !== 1n)
781
+ throw Error("invalid Credit unlimited byte");
782
+ note[k] = k === "unlimited" ? n === 1n : k.endsWith("Identity") ? hexField(n) : n;
783
+ offset += size;
784
+ }
785
+ const keys = () => {
786
+ const k = {
787
+ viewingPublicKey: plain.slice(offset, offset + 33),
788
+ clueKey: plain.slice(offset + 33, offset + 65)
789
+ };
790
+ offset += 65;
791
+ return k;
792
+ };
793
+ const ownerReceivingKeys = keys(), spenderReceivingKeys = keys();
794
+ note.payload = readPayload(plain, offset);
795
+ return normalizeCreditDeliveryState({
796
+ note,
797
+ ownerReceivingKeys,
798
+ spenderReceivingKeys
799
+ });
800
+ }
801
+ };
802
+
803
+ // src/delivery/delivery-codec.ts
804
+ var MAX_CIPHERTEXT_BYTES = 4096;
805
+ function deliveryHeader(kind) {
806
+ if (kind !== "funds" && kind !== "credit") throw new Error("unsupported delivery kind");
807
+ return kind === "credit" ? 130 : 1;
808
+ }
809
+ function decodeDeliveryHeader(header) {
810
+ if (!Number.isInteger(header) || header < 0 || header > 255)
811
+ throw new Error("delivery header must be one byte");
812
+ const kind = header >>> 7 ? "credit" : "funds";
813
+ const version = header & 127;
814
+ if (version === 0) throw new Error("invalid envelope version");
815
+ return { kind, version };
816
+ }
817
+ function deliveryCodec(header) {
818
+ const { kind, version } = decodeDeliveryHeader(header);
819
+ if (version !== (kind === "credit" ? 2 : 1))
820
+ throw new Error(`unsupported envelope version ${version}`);
821
+ const codec = kind === "funds" ? fundsEnvelopeV1 : creditEnvelopeV2;
822
+ return {
823
+ ...codec,
824
+ domain: `Invisi.${kind === "funds" ? "Note" : "Credit"}Delivery.v${kind === "credit" ? 2 : 1}`
825
+ };
826
+ }
827
+ function validateDeliveryCiphertext(value, kind) {
828
+ const data = Uint8Array.from((0, import_ethers.getBytes)(value));
829
+ if (data.length === 0 || data.length > MAX_CIPHERTEXT_BYTES)
830
+ throw new Error("invalid envelope length");
831
+ const codec = deliveryCodec(data[0]);
832
+ if (kind !== void 0 && codec.kind !== kind) throw new Error("unexpected envelope kind");
833
+ if (data.length < codec.minimum || data.length > codec.maximum)
834
+ throw new Error("invalid envelope length");
835
+ return data;
836
+ }
837
+
838
+ // src/delivery/envelope.ts
839
+ var import_secp256k12 = require("@noble/curves/secp256k1");
840
+
841
+ // src/delivery/binary.ts
842
+ var ascii = (value) => Uint8Array.from(value, (character) => character.charCodeAt(0));
843
+ function concat2(...parts) {
844
+ const out = new Uint8Array(parts.reduce((size, p) => size + p.length, 0));
845
+ let offset = 0;
846
+ for (const part of parts) {
847
+ out.set(part, offset);
848
+ offset += part.length;
849
+ }
850
+ return out;
851
+ }
852
+ function bytes(value, length) {
853
+ let out;
854
+ if (typeof value === "string") {
855
+ if (!/^0x(?:[0-9a-fA-F]{2})*$/.test(value)) throw new Error("invalid hexadecimal bytes");
856
+ out = Uint8Array.from(value.slice(2).match(/../g) ?? [], (b) => parseInt(b, 16));
857
+ } else if (value instanceof Uint8Array) out = Uint8Array.from(value);
858
+ else throw new Error("expected hexadecimal bytes or Uint8Array");
859
+ if (out.length !== length) throw new Error(`expected ${length} bytes`);
860
+ return out;
861
+ }
862
+ function uint3(value, bits, name) {
863
+ if (value < 0n || value >= 1n << BigInt(bits))
864
+ throw new RangeError(`${name} out of uint${bits} range`);
865
+ }
866
+ function field3(value, name) {
867
+ if (value < 0n || value >= FIELD_MODULUS)
868
+ throw new RangeError(`${name} out of BN254 field range`);
869
+ }
870
+ function encode2(value, length = 32) {
871
+ uint3(value, length * 8, "encoded value");
872
+ const out = new Uint8Array(length);
873
+ for (let i = length - 1; i >= 0; i--) {
874
+ out[i] = Number(value & 255n);
875
+ value >>= 8n;
876
+ }
877
+ return out;
878
+ }
879
+
880
+ // src/delivery/validation.ts
881
+ function validateContext(context, tokenAddress) {
882
+ uint3(context.chainId, 64, "chainId");
883
+ uint3(context.protocolAddress, 160, "protocolAddress");
884
+ uint3(tokenAddress, 160, "tokenAddress");
885
+ field3(BigInt(context.outputCommitment), "outputCommitment");
886
+ }
887
+ async function creditCommitment(context, note) {
888
+ validateContext(context, note.tokenAddress);
889
+ assertNoteContext(note, context);
890
+ const commitment = await computeCreditCommitment(note);
891
+ if (BigInt(commitment) !== BigInt(context.outputCommitment))
892
+ throw new Error("credit commitment mismatch");
893
+ }
894
+
895
+ // src/delivery/envelope.ts
896
+ function aad(domain, context, tokenAddress, header, role) {
897
+ validateContext(context, tokenAddress);
898
+ return concat2(
899
+ domain,
900
+ header,
901
+ new Uint8Array([role]),
902
+ encode2(context.chainId, 8),
903
+ encode2(context.protocolAddress, 20),
904
+ encode2(tokenAddress, 20),
905
+ encode2(BigInt(context.outputCommitment))
906
+ );
907
+ }
908
+ function privateKey(value) {
909
+ const key = bytes(value, 32);
910
+ if (!import_secp256k12.secp256k1.utils.isValidPrivateKey(key)) throw new Error("invalid viewing private key");
911
+ return key;
912
+ }
913
+ function publicKey(value) {
914
+ const key = bytes(value, 33);
915
+ if (key[0] !== 2 && key[0] !== 3) throw new Error("expected compressed secp256k1 public key");
916
+ import_secp256k12.secp256k1.ProjectivePoint.fromHex(key);
917
+ return key;
918
+ }
919
+ function viewingPublicKey(key) {
920
+ return import_secp256k12.secp256k1.getPublicKey(privateKey(key), true);
921
+ }
922
+ function random(length) {
923
+ return crypto.getRandomValues(new Uint8Array(length));
924
+ }
925
+ function ephemeralKey() {
926
+ for (; ; ) {
927
+ const key = random(32);
928
+ if (import_secp256k12.secp256k1.utils.isValidPrivateKey(key)) return key;
929
+ }
930
+ }
931
+ var buffer = (value) => Uint8Array.from(value).buffer;
932
+ async function derivedKey(key, peer, header, recipient, domain, extractable = false) {
933
+ const secret = import_secp256k12.secp256k1.getSharedSecret(key, peer, true).slice(1);
934
+ const material = await crypto.subtle.importKey("raw", buffer(secret), "HKDF", false, [
935
+ "deriveKey"
936
+ ]);
937
+ try {
938
+ return await crypto.subtle.deriveKey(
939
+ {
940
+ name: "HKDF",
941
+ hash: "SHA-256",
942
+ salt: buffer(header.slice(34, 50)),
943
+ info: buffer(concat2(domain, header.slice(1, 34), recipient))
944
+ },
945
+ material,
946
+ { name: "AES-GCM", length: 256 },
947
+ extractable,
948
+ ["encrypt", "decrypt"]
949
+ );
950
+ } finally {
951
+ secret.fill(0);
952
+ }
953
+ }
954
+ async function seal(viewingKey, plaintext, context, tokenAddress, headerByte, role) {
955
+ const peer = publicKey(viewingKey), key = ephemeralKey();
956
+ const salt = random(16), iv = random(12), domain = deliveryDomain(headerByte);
957
+ const header = concat2(
958
+ new Uint8Array([headerByte]),
959
+ import_secp256k12.secp256k1.getPublicKey(key, true),
960
+ salt,
961
+ iv
962
+ );
963
+ const additionalData = aad(domain, context, tokenAddress, header, role);
964
+ try {
965
+ const encrypted = await crypto.subtle.encrypt(
966
+ {
967
+ name: "AES-GCM",
968
+ iv: buffer(iv),
969
+ additionalData: buffer(additionalData),
970
+ tagLength: 128
971
+ },
972
+ await derivedKey(key, peer, header, peer, domain),
973
+ buffer(plaintext)
974
+ );
975
+ return concat2(header, new Uint8Array(encrypted));
976
+ } finally {
977
+ key.fill(0);
978
+ plaintext.fill(0);
979
+ }
980
+ }
981
+ async function open(key, envelope, context, headerByte, role, payloadKey = false) {
982
+ const data = envelopeBytes(envelope, deliveryCodec(headerByte).kind === "credit");
983
+ if (data[0] !== headerByte) throw new Error("unsupported envelope version");
984
+ const domain = deliveryDomain(headerByte);
985
+ const additionalData = aad(domain, context, context.tokenAddress, data.slice(0, 62), role);
986
+ const localKey = payloadKey ? bytes(key, 32) : privateKey(key);
987
+ try {
988
+ const aes = payloadKey ? await crypto.subtle.importKey("raw", buffer(bytes(key, 32)), "AES-GCM", false, [
989
+ "decrypt"
990
+ ]) : await derivedKey(
991
+ localKey,
992
+ publicKey(data.slice(1, 34)),
993
+ data.slice(0, 62),
994
+ import_secp256k12.secp256k1.getPublicKey(localKey, true),
995
+ domain
996
+ );
997
+ const decrypted = await crypto.subtle.decrypt(
998
+ {
999
+ name: "AES-GCM",
1000
+ iv: buffer(data.slice(50, 62)),
1001
+ additionalData: buffer(additionalData),
1002
+ tagLength: 128
1003
+ },
1004
+ aes,
1005
+ buffer(data.slice(62))
1006
+ );
1007
+ return new Uint8Array(decrypted);
1008
+ } finally {
1009
+ localKey.fill(0);
1010
+ }
1011
+ }
1012
+ function deliveryDomain(headerByte) {
1013
+ return ascii(deliveryCodec(headerByte).domain);
1014
+ }
1015
+ function envelopeBytes(value, credit) {
1016
+ return validateDeliveryCiphertext(value, credit ? "credit" : "funds");
1017
+ }
1018
+
1019
+ // src/delivery/encryption.ts
1020
+ function copyPayload(value, codec) {
1021
+ if (!(value instanceof Uint8Array)) throw new Error("codec encode must return Uint8Array");
1022
+ if (value.length + 78 < codec.minimum || value.length + 78 > codec.maximum)
1023
+ throw new Error("invalid codec payload length");
1024
+ return Uint8Array.from(value);
1025
+ }
1026
+ function creditRole(role) {
1027
+ if (role !== "owner" && role !== "spender")
1028
+ throw new Error("Credit role must be owner or spender");
1029
+ return role === "owner" ? 1 : 2;
1030
+ }
1031
+ function matchCreditRecipient(state, role, recipient) {
1032
+ const keys = role === "owner" ? state.ownerReceivingKeys : state.spenderReceivingKeys;
1033
+ if (!keys.viewingPublicKey.every((value, index) => value === recipient[index]))
1034
+ throw new Error("recipient receiving key mismatch");
1035
+ }
1036
+ async function encryptCreditState(viewingKey, state, context) {
1037
+ const scopedState = normalizeCreditDeliveryState(state), scopedNote = scopedState.note;
1038
+ const scopedContext = { ...context };
1039
+ const codec = deliveryCodec(deliveryHeader("credit"));
1040
+ if (codec.kind !== "credit") throw new Error("unexpected envelope kind");
1041
+ creditRole(scopedContext.role);
1042
+ matchCreditRecipient(scopedState, scopedContext.role, publicKey(viewingKey));
1043
+ await creditCommitment(scopedContext, scopedNote);
1044
+ const plaintext = copyPayload(codec.encode(structuredClone(scopedState)), codec);
1045
+ return seal(
1046
+ viewingKey,
1047
+ plaintext,
1048
+ scopedContext,
1049
+ scopedNote.tokenAddress,
1050
+ deliveryHeader("credit"),
1051
+ creditRole(scopedContext.role)
1052
+ );
1053
+ }
1054
+ async function readCredit(key, envelope, context, payloadKey = false) {
1055
+ const authenticatedContext = { ...context };
1056
+ const data = envelopeBytes(envelope, true);
1057
+ const plain = await open(
1058
+ key,
1059
+ data,
1060
+ authenticatedContext,
1061
+ data[0],
1062
+ creditRole(authenticatedContext.role),
1063
+ payloadKey
1064
+ );
1065
+ try {
1066
+ const codec = deliveryCodec(data[0]);
1067
+ if (codec.kind !== "credit") throw new Error("unexpected envelope kind");
1068
+ const state = normalizeCreditDeliveryState(
1069
+ structuredClone(codec.decode(plain, Object.freeze({ ...authenticatedContext })))
1070
+ );
1071
+ const note = state.note;
1072
+ if (BigInt(
1073
+ authenticatedContext.role === "owner" ? note.ownerWalletIdentity : note.spenderWalletIdentity
1074
+ ) !== BigInt(authenticatedContext.ownerAddress))
1075
+ throw new Error("recipient owner address mismatch");
1076
+ if (!payloadKey)
1077
+ matchCreditRecipient(state, authenticatedContext.role, viewingPublicKey(key));
1078
+ if (note.tokenAddress !== authenticatedContext.tokenAddress)
1079
+ throw new Error("Credit token context mismatch");
1080
+ await creditCommitment(authenticatedContext, note);
1081
+ return {
1082
+ ...state,
1083
+ note: { ...state.note, payload: Uint8Array.from(state.note.payload ?? []) }
1084
+ };
1085
+ } finally {
1086
+ plain.fill(0);
1087
+ }
1088
+ }
1089
+ function decryptCreditState(key, envelope, context) {
1090
+ return readCredit(key, envelope, context);
1091
+ }
1092
+ // Annotate the CommonJS export names for ESM import in node:
1093
+ 0 && (module.exports = {
1094
+ CREDIT_POLICY_FIELDS,
1095
+ CREDIT_USAGE_FIELDS,
1096
+ applyCreditDrawUsage,
1097
+ computeCreditCommitment,
1098
+ computeCreditNullifier,
1099
+ computeCreditRecoveryPad,
1100
+ computeCreditSharedKeyHash,
1101
+ creditPeriods,
1102
+ decryptCreditState,
1103
+ deriveCreditState,
1104
+ deriveCreditStateNonce,
1105
+ deriveCreditUpdate,
1106
+ encryptCreditState,
1107
+ normalizeCreditDeliveryState,
1108
+ normalizeCreditPolicy,
1109
+ normalizeCreditState,
1110
+ normalizeCreditUsage,
1111
+ recoverCreditState
1112
+ });
1113
+ //# sourceMappingURL=credit.cjs.map