@agirails/sdk 4.4.8 → 4.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builders/DeliveryProofBuilder.d.ts +224 -13
- package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -1
- package/dist/builders/DeliveryProofBuilder.js +247 -13
- package/dist/builders/DeliveryProofBuilder.js.map +1 -1
- package/dist/cli/agirails.d.ts +85 -1
- package/dist/cli/agirails.d.ts.map +1 -1
- package/dist/cli/agirails.js +429 -154
- package/dist/cli/agirails.js.map +1 -1
- package/dist/cli/commands/init.d.ts +54 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +193 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/receipt.d.ts +70 -2
- package/dist/cli/commands/receipt.d.ts.map +1 -1
- package/dist/cli/commands/receipt.js +218 -3
- package/dist/cli/commands/receipt.js.map +1 -1
- package/dist/cli/commands/test.d.ts +77 -1
- package/dist/cli/commands/test.d.ts.map +1 -1
- package/dist/cli/commands/test.js +264 -2
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/lib/runRequest.d.ts +90 -0
- package/dist/cli/lib/runRequest.d.ts.map +1 -1
- package/dist/cli/lib/runRequest.js +300 -9
- package/dist/cli/lib/runRequest.js.map +1 -1
- package/dist/cli/lib/sentinelReflections.d.ts +111 -0
- package/dist/cli/lib/sentinelReflections.d.ts.map +1 -0
- package/dist/cli/lib/sentinelReflections.js +193 -0
- package/dist/cli/lib/sentinelReflections.js.map +1 -0
- package/dist/delivery/MockDeliveryChannel.d.ts +208 -0
- package/dist/delivery/MockDeliveryChannel.d.ts.map +1 -0
- package/dist/delivery/MockDeliveryChannel.js +445 -0
- package/dist/delivery/MockDeliveryChannel.js.map +1 -0
- package/dist/delivery/RelayDeliveryChannel.d.ts +176 -0
- package/dist/delivery/RelayDeliveryChannel.d.ts.map +1 -0
- package/dist/delivery/RelayDeliveryChannel.js +377 -0
- package/dist/delivery/RelayDeliveryChannel.js.map +1 -0
- package/dist/delivery/channel.d.ts +282 -0
- package/dist/delivery/channel.d.ts.map +1 -0
- package/dist/delivery/channel.js +76 -0
- package/dist/delivery/channel.js.map +1 -0
- package/dist/delivery/channelLog.d.ts +115 -0
- package/dist/delivery/channelLog.d.ts.map +1 -0
- package/dist/delivery/channelLog.js +94 -0
- package/dist/delivery/channelLog.js.map +1 -0
- package/dist/delivery/crypto.d.ts +312 -0
- package/dist/delivery/crypto.d.ts.map +1 -0
- package/dist/delivery/crypto.js +495 -0
- package/dist/delivery/crypto.js.map +1 -0
- package/dist/delivery/eip712.d.ts +248 -0
- package/dist/delivery/eip712.d.ts.map +1 -0
- package/dist/delivery/eip712.js +397 -0
- package/dist/delivery/eip712.js.map +1 -0
- package/dist/delivery/envelopeBuilder.d.ts +531 -0
- package/dist/delivery/envelopeBuilder.d.ts.map +1 -0
- package/dist/delivery/envelopeBuilder.js +832 -0
- package/dist/delivery/envelopeBuilder.js.map +1 -0
- package/dist/delivery/index.d.ts +53 -0
- package/dist/delivery/index.d.ts.map +1 -0
- package/dist/delivery/index.js +143 -0
- package/dist/delivery/index.js.map +1 -0
- package/dist/delivery/keys.d.ts +344 -0
- package/dist/delivery/keys.d.ts.map +1 -0
- package/dist/delivery/keys.js +513 -0
- package/dist/delivery/keys.js.map +1 -0
- package/dist/delivery/nonce-keys.d.ts +93 -0
- package/dist/delivery/nonce-keys.d.ts.map +1 -0
- package/dist/delivery/nonce-keys.js +88 -0
- package/dist/delivery/nonce-keys.js.map +1 -0
- package/dist/delivery/setupBuilder.d.ts +403 -0
- package/dist/delivery/setupBuilder.d.ts.map +1 -0
- package/dist/delivery/setupBuilder.js +554 -0
- package/dist/delivery/setupBuilder.js.map +1 -0
- package/dist/delivery/types.d.ts +722 -0
- package/dist/delivery/types.d.ts.map +1 -0
- package/dist/delivery/types.js +150 -0
- package/dist/delivery/types.js.map +1 -0
- package/dist/delivery/validate.d.ts +288 -0
- package/dist/delivery/validate.d.ts.map +1 -0
- package/dist/delivery/validate.js +648 -0
- package/dist/delivery/validate.js.map +1 -0
- package/dist/level1/Agent.d.ts +130 -0
- package/dist/level1/Agent.d.ts.map +1 -1
- package/dist/level1/Agent.js +248 -0
- package/dist/level1/Agent.js.map +1 -1
- package/dist/level1/types/Options.d.ts +62 -0
- package/dist/level1/types/Options.d.ts.map +1 -1
- package/dist/level1/types/Options.js +22 -0
- package/dist/level1/types/Options.js.map +1 -1
- package/dist/runtime/MockRuntime.d.ts +32 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.js +44 -0
- package/dist/runtime/MockRuntime.js.map +1 -1
- package/dist/wallet/aa/BundlerClient.d.ts.map +1 -1
- package/dist/wallet/aa/BundlerClient.js +18 -3
- package/dist/wallet/aa/BundlerClient.js.map +1 -1
- package/dist/wallet/aa/PaymasterClient.d.ts.map +1 -1
- package/dist/wallet/aa/PaymasterClient.js +4 -1
- package/dist/wallet/aa/PaymasterClient.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* AIP-16 Delivery Surface — AES-256-GCM AEAD + Body Hashing (Phase 2a Foundation)
|
|
4
|
+
* ==============================================================================
|
|
5
|
+
*
|
|
6
|
+
* Authenticated encryption primitives for the `x25519-aes256gcm-v1`
|
|
7
|
+
* delivery scheme of AIP-16 Rev 5.
|
|
8
|
+
*
|
|
9
|
+
* This module sits one layer above `./keys.ts` (which produces the
|
|
10
|
+
* 32-byte session key via X25519 ECDH + HKDF-SHA256) and one layer
|
|
11
|
+
* below the envelope builders (`./envelopeBuilder.ts`, later phase),
|
|
12
|
+
* which assemble the ciphertext + nonce + tag + signature into the
|
|
13
|
+
* wire envelope.
|
|
14
|
+
*
|
|
15
|
+
* ## Scope of this file
|
|
16
|
+
*
|
|
17
|
+
* - {@link encryptBody}: seal a UTF-8 string or raw byte body with
|
|
18
|
+
* AES-256-GCM, returning ciphertext + 12-byte nonce + 16-byte tag.
|
|
19
|
+
* - {@link decryptBody}: inverse — verify the GCM tag and return the
|
|
20
|
+
* plaintext.
|
|
21
|
+
* - {@link bodyHash}: keccak256 of the UTF-8 / raw bytes, in the exact
|
|
22
|
+
* form used for the `payloadHash` field of the signed EIP-712
|
|
23
|
+
* projection.
|
|
24
|
+
* - Hex format helpers ({@link bytesToHex}, {@link bytesFromHex}) for
|
|
25
|
+
* ciphertext / nonce / tag serialization at the wire boundary.
|
|
26
|
+
*
|
|
27
|
+
* ## Library choice: `node:crypto`
|
|
28
|
+
*
|
|
29
|
+
* We use Node's built-in AES-GCM (`createCipheriv('aes-256-gcm', …)`)
|
|
30
|
+
* rather than `@noble/ciphers`. Reasons:
|
|
31
|
+
*
|
|
32
|
+
* 1. AES-256-GCM is a *standard* AEAD; the implementation surface is
|
|
33
|
+
* small and audited as part of OpenSSL (the engine behind
|
|
34
|
+
* `node:crypto`).
|
|
35
|
+
* 2. Zero new dependencies — matches the design constraint in the
|
|
36
|
+
* Phase 2a task brief.
|
|
37
|
+
* 3. The `setAuthTag` / `getAuthTag` pattern is mechanical and easy
|
|
38
|
+
* to audit for "did we actually verify the tag before returning
|
|
39
|
+
* plaintext?" (`decipher.final()` throws on tag mismatch).
|
|
40
|
+
*
|
|
41
|
+
* ## AAD (Additional Authenticated Data) — H5 defense-in-depth
|
|
42
|
+
*
|
|
43
|
+
* Both {@link encryptBody} and {@link decryptBody} accept an OPTIONAL
|
|
44
|
+
* `aad` byte buffer. When supplied, the bytes are fed into GCM via
|
|
45
|
+
* `cipher.setAAD(aad)` / `decipher.setAAD(aad)` — they are *not*
|
|
46
|
+
* encrypted, but the GCM authentication tag commits to them, so a
|
|
47
|
+
* decryption with the wrong AAD fails closed with a tag mismatch.
|
|
48
|
+
*
|
|
49
|
+
* For the `x25519-aes256gcm-v1` scheme the envelope builder constructs
|
|
50
|
+
*
|
|
51
|
+
* aad = txId_bytes (32) || signerAddress_bytes (20) // 52 bytes
|
|
52
|
+
*
|
|
53
|
+
* and passes it to both encrypt and decrypt. This binds the GCM
|
|
54
|
+
* authentication to the on-chain transaction id and the EOA that
|
|
55
|
+
* signed the envelope, so a misrouted envelope (correct ciphertext +
|
|
56
|
+
* nonce + tag + sessionKey, but delivered to a different `txId` or
|
|
57
|
+
* `signerAddress`) cannot be opened — defense-in-depth on top of the
|
|
58
|
+
* EIP-712 signature over `txId` and `payloadHash`.
|
|
59
|
+
*
|
|
60
|
+
* Because the channel is gated behind the Phase 2f feature flag and
|
|
61
|
+
* no in-flight `x25519-aes256gcm-v1` envelopes exist in production, we
|
|
62
|
+
* change the AAD inline within the existing scheme tag rather than
|
|
63
|
+
* minting a `-v2` suffix; the scheme name stays `x25519-aes256gcm-v1`.
|
|
64
|
+
*
|
|
65
|
+
* AAD is OPTIONAL at the primitive level. Callers that omit it get
|
|
66
|
+
* the legacy "AAD = empty" behavior (still interoperable with prior
|
|
67
|
+
* versions of the function). The envelope builder always supplies AAD.
|
|
68
|
+
*
|
|
69
|
+
* ## Memory hygiene
|
|
70
|
+
*
|
|
71
|
+
* `sessionKey` and plaintext are held in plain `Uint8Array`s. Like
|
|
72
|
+
* `./keys.ts`, this module does not attempt to zero memory — V8 makes
|
|
73
|
+
* no such guarantees, and the SDK target environments (Node + Bun)
|
|
74
|
+
* inherit that limitation. Callers SHOULD let secrets go out of scope
|
|
75
|
+
* promptly after use.
|
|
76
|
+
*
|
|
77
|
+
* @module delivery/crypto
|
|
78
|
+
* @see ./keys — produces the 32-byte session key consumed here
|
|
79
|
+
* @see ./eip712 — signs the `payloadHash` produced by {@link bodyHash}
|
|
80
|
+
* @see {@link https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf NIST SP 800-38D — GCM mode}
|
|
81
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc5116 RFC 5116 — AEAD interface}
|
|
82
|
+
*/
|
|
83
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
84
|
+
exports.bytesFromHex = exports.bytesToHex = exports.bodyHash = exports.decryptBody = exports.encryptBody = exports.AES_KEY_LENGTH = exports.AES_GCM_TAG_LENGTH = exports.AES_GCM_NONCE_LENGTH = void 0;
|
|
85
|
+
const node_crypto_1 = require("node:crypto");
|
|
86
|
+
const ethers_1 = require("ethers");
|
|
87
|
+
const keys_1 = require("./keys");
|
|
88
|
+
// ============================================================================
|
|
89
|
+
// Constants
|
|
90
|
+
// ============================================================================
|
|
91
|
+
/**
|
|
92
|
+
* Length (in bytes) of the AES-256-GCM nonce / IV.
|
|
93
|
+
*
|
|
94
|
+
* Twelve bytes is the GCM-standard length (NIST SP 800-38D §5.2.1.1).
|
|
95
|
+
* Any other length is technically permitted by the spec but triggers
|
|
96
|
+
* an additional GHASH step and is interoperable only by convention;
|
|
97
|
+
* AIP-16 v1 mandates 12 bytes to keep the wire format unambiguous.
|
|
98
|
+
*
|
|
99
|
+
* We sample the nonce from `randomBytes(12)` per-encryption. The
|
|
100
|
+
* 2^96 nonce space is more than adequate for the AIP-16 use case
|
|
101
|
+
* (one nonce per delivery envelope per session key, with session keys
|
|
102
|
+
* themselves bound to a single transaction via HKDF).
|
|
103
|
+
*/
|
|
104
|
+
exports.AES_GCM_NONCE_LENGTH = 12;
|
|
105
|
+
/**
|
|
106
|
+
* Length (in bytes) of the AES-256-GCM authentication tag.
|
|
107
|
+
*
|
|
108
|
+
* Sixteen bytes is the maximum (full-strength) tag length permitted
|
|
109
|
+
* by GCM; NIST SP 800-38D recommends this size when the application
|
|
110
|
+
* cannot tolerate any forgery probability. The wire format reserves
|
|
111
|
+
* a fixed 16-byte slot for the tag.
|
|
112
|
+
*/
|
|
113
|
+
exports.AES_GCM_TAG_LENGTH = 16;
|
|
114
|
+
/**
|
|
115
|
+
* Length (in bytes) of an AES-256 key. Equal to
|
|
116
|
+
* {@link DELIVERY_SESSION_KEY_LENGTH} (re-exported from `./keys`) so
|
|
117
|
+
* callers do not have to import both files just for the length check.
|
|
118
|
+
*/
|
|
119
|
+
exports.AES_KEY_LENGTH = keys_1.DELIVERY_SESSION_KEY_LENGTH;
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// Internal helpers
|
|
122
|
+
// ============================================================================
|
|
123
|
+
/**
|
|
124
|
+
* Convert a `string | Uint8Array` plaintext to bytes. UTF-8 is the
|
|
125
|
+
* canonical text encoding for AIP-16 envelope bodies; any other
|
|
126
|
+
* encoding (UTF-16, Latin-1, …) MUST be transcoded to UTF-8 by the
|
|
127
|
+
* caller before calling {@link encryptBody}.
|
|
128
|
+
*
|
|
129
|
+
* @internal
|
|
130
|
+
*/
|
|
131
|
+
function toBytes(value, field) {
|
|
132
|
+
if (typeof value === 'string') {
|
|
133
|
+
return new Uint8Array(Buffer.from(value, 'utf8'));
|
|
134
|
+
}
|
|
135
|
+
if (value instanceof Uint8Array) {
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `${field} must be a string or Uint8Array, got ${typeof value}`, { field, type: typeof value });
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Hex alphabet for the lowercase no-Buffer hex encoder. Kept in lock-
|
|
142
|
+
* step with `./keys.ts` so both files produce byte-identical output.
|
|
143
|
+
*
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
const HEX_CHARS = '0123456789abcdef';
|
|
147
|
+
// ============================================================================
|
|
148
|
+
// Public API: AES-256-GCM
|
|
149
|
+
// ============================================================================
|
|
150
|
+
/**
|
|
151
|
+
* Encrypt a delivery envelope body with AES-256-GCM using the supplied
|
|
152
|
+
* session key.
|
|
153
|
+
*
|
|
154
|
+
* The session key MUST have been produced by
|
|
155
|
+
* {@link import('./keys').deriveSessionKey} (32 bytes, HKDF-SHA256
|
|
156
|
+
* output bound to the on-chain `txId`).
|
|
157
|
+
*
|
|
158
|
+
* A fresh 12-byte nonce is sampled from `randomBytes` per call.
|
|
159
|
+
* Re-using a (key, nonce) pair is *catastrophic* for GCM — it leaks
|
|
160
|
+
* the GHASH key, allowing both decryption of past messages and
|
|
161
|
+
* forgery of future ones. With session keys scoped to one transaction
|
|
162
|
+
* and nonces randomized per envelope, the probability of collision
|
|
163
|
+
* over realistic envelope counts is negligible.
|
|
164
|
+
*
|
|
165
|
+
* AAD is OPTIONAL. When supplied, the bytes are committed by the GCM
|
|
166
|
+
* tag (defense-in-depth — see the H5 section of the module-level docs).
|
|
167
|
+
* Decryption with a different AAD (or with no AAD at all when the
|
|
168
|
+
* encrypt side used one) will fail with `crypto_decrypt_failed`.
|
|
169
|
+
*
|
|
170
|
+
* @param plaintext - Body bytes to encrypt. A `string` is interpreted
|
|
171
|
+
* as UTF-8; pre-encoded `Uint8Array` is passed through verbatim.
|
|
172
|
+
* @param sessionKey - 32-byte AES-256-GCM key from `deriveSessionKey`.
|
|
173
|
+
* @param aad - Optional Additional Authenticated Data. When omitted,
|
|
174
|
+
* no AAD is fed into GCM (legacy behavior). When supplied, MUST be a
|
|
175
|
+
* `Uint8Array`; mismatched AAD at decrypt time fails tag verification.
|
|
176
|
+
* @returns {@link EncryptResult} carrying ciphertext, nonce, and tag.
|
|
177
|
+
* @throws {DeliveryCryptoError} `crypto_encrypt_failed` if
|
|
178
|
+
* `sessionKey` is malformed (not a `Uint8Array` of length 32), if
|
|
179
|
+
* `plaintext` is the wrong type, if `aad` is supplied as a non-bytes
|
|
180
|
+
* value, or if `node:crypto` raises.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const key = deriveSessionKey(shared, txId);
|
|
185
|
+
* // AAD = txId_bytes || signerAddress_bytes (H5 binding)
|
|
186
|
+
* const aad = new Uint8Array(52);
|
|
187
|
+
* aad.set(bytesFromHex(txId), 0);
|
|
188
|
+
* aad.set(bytesFromHex(signerAddress), 32);
|
|
189
|
+
* const { ciphertext, nonce, tag } = encryptBody('{"result":"ok"}', key, aad);
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
function encryptBody(plaintext, sessionKey, aad) {
|
|
193
|
+
// ── Validate session key shape ──────────────────────────────────
|
|
194
|
+
if (!(sessionKey instanceof Uint8Array)) {
|
|
195
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `sessionKey must be a Uint8Array, got ${typeof sessionKey}`, { field: 'sessionKey', type: typeof sessionKey });
|
|
196
|
+
}
|
|
197
|
+
if (sessionKey.length !== exports.AES_KEY_LENGTH) {
|
|
198
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `sessionKey must be exactly ${exports.AES_KEY_LENGTH} bytes (got ${sessionKey.length})`, {
|
|
199
|
+
field: 'sessionKey',
|
|
200
|
+
expectedLength: exports.AES_KEY_LENGTH,
|
|
201
|
+
actualLength: sessionKey.length,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// ── Validate AAD shape (if provided) ────────────────────────────
|
|
205
|
+
//
|
|
206
|
+
// We accept either `undefined` (no-AAD legacy behavior) or a
|
|
207
|
+
// `Uint8Array` (any length, including zero). Anything else is a
|
|
208
|
+
// caller bug and surfaces as `crypto_encrypt_failed` so it fails
|
|
209
|
+
// closed at the encrypt boundary rather than producing an envelope
|
|
210
|
+
// the buyer cannot open.
|
|
211
|
+
if (aad !== undefined && !(aad instanceof Uint8Array)) {
|
|
212
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `aad must be a Uint8Array when supplied, got ${typeof aad}`, { field: 'aad', type: typeof aad });
|
|
213
|
+
}
|
|
214
|
+
// ── Coerce plaintext to bytes ───────────────────────────────────
|
|
215
|
+
const ptBytes = toBytes(plaintext, 'plaintext');
|
|
216
|
+
// ── Sample a fresh 12-byte nonce ────────────────────────────────
|
|
217
|
+
let nonce;
|
|
218
|
+
try {
|
|
219
|
+
nonce = new Uint8Array((0, node_crypto_1.randomBytes)(exports.AES_GCM_NONCE_LENGTH));
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `randomBytes(${exports.AES_GCM_NONCE_LENGTH}) failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err.message : String(err) });
|
|
223
|
+
}
|
|
224
|
+
// ── Encrypt ─────────────────────────────────────────────────────
|
|
225
|
+
let ciphertext;
|
|
226
|
+
let tag;
|
|
227
|
+
try {
|
|
228
|
+
const cipher = (0, node_crypto_1.createCipheriv)('aes-256-gcm', sessionKey, nonce, {
|
|
229
|
+
authTagLength: exports.AES_GCM_TAG_LENGTH,
|
|
230
|
+
});
|
|
231
|
+
// H5 binding: when AAD is supplied, feed it into GCM BEFORE any
|
|
232
|
+
// ciphertext bytes are produced. AAD is authenticated but not
|
|
233
|
+
// encrypted — the tag will only verify on decrypt if the same AAD
|
|
234
|
+
// is presented. `setAAD` MUST be called before `update` per the
|
|
235
|
+
// node:crypto contract (the underlying OpenSSL state machine
|
|
236
|
+
// forbids AAD after ciphertext input).
|
|
237
|
+
if (aad !== undefined) {
|
|
238
|
+
cipher.setAAD(aad);
|
|
239
|
+
}
|
|
240
|
+
const part1 = cipher.update(ptBytes);
|
|
241
|
+
const part2 = cipher.final();
|
|
242
|
+
// Concatenate as a single Uint8Array. `Buffer.concat` returns a
|
|
243
|
+
// Buffer (subclass of Uint8Array); we wrap to a plain Uint8Array
|
|
244
|
+
// view to avoid leaking the Buffer subclass to consumers, which
|
|
245
|
+
// matters for downstream `instanceof Uint8Array` checks across
|
|
246
|
+
// realms / workers.
|
|
247
|
+
const combined = Buffer.concat([part1, part2]);
|
|
248
|
+
ciphertext = new Uint8Array(combined.buffer, combined.byteOffset, combined.byteLength);
|
|
249
|
+
const rawTag = cipher.getAuthTag();
|
|
250
|
+
tag = new Uint8Array(rawTag.buffer, rawTag.byteOffset, rawTag.byteLength);
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `AES-256-GCM encryption failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err.message : String(err) });
|
|
254
|
+
}
|
|
255
|
+
// ── Defensive length checks (paranoia) ──────────────────────────
|
|
256
|
+
if (tag.length !== exports.AES_GCM_TAG_LENGTH) {
|
|
257
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `GCM authentication tag has unexpected length: ${tag.length}`, { expectedLength: exports.AES_GCM_TAG_LENGTH, actualLength: tag.length });
|
|
258
|
+
}
|
|
259
|
+
if (nonce.length !== exports.AES_GCM_NONCE_LENGTH) {
|
|
260
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `GCM nonce has unexpected length: ${nonce.length}`, { expectedLength: exports.AES_GCM_NONCE_LENGTH, actualLength: nonce.length });
|
|
261
|
+
}
|
|
262
|
+
return { ciphertext, nonce, tag };
|
|
263
|
+
}
|
|
264
|
+
exports.encryptBody = encryptBody;
|
|
265
|
+
/**
|
|
266
|
+
* Decrypt and authenticate an AES-256-GCM ciphertext produced by
|
|
267
|
+
* {@link encryptBody} (or an interoperable peer).
|
|
268
|
+
*
|
|
269
|
+
* The GCM authentication tag is verified inside `decipher.final()` —
|
|
270
|
+
* if the tag does not match, `node:crypto` throws and we re-raise as
|
|
271
|
+
* `DeliveryCryptoError('crypto_decrypt_failed')`. This is the *only*
|
|
272
|
+
* integrity check on the envelope body bytes; pair it with EIP-712
|
|
273
|
+
* signature verification one layer up to also bind the body to a
|
|
274
|
+
* specific signer.
|
|
275
|
+
*
|
|
276
|
+
* AAD is OPTIONAL but MUST match what the encrypt side used. The GCM
|
|
277
|
+
* tag commits to the AAD bytes; supplying the wrong AAD (or omitting
|
|
278
|
+
* AAD when the encrypt side supplied one, or vice versa) produces a
|
|
279
|
+
* tag-mismatch error, surfaced here as `crypto_decrypt_failed`. This
|
|
280
|
+
* is the H5 misrouting defense — see the module-level AAD section.
|
|
281
|
+
*
|
|
282
|
+
* @param ciphertext - GCM ciphertext as raw bytes.
|
|
283
|
+
* @param sessionKey - 32-byte AES-256-GCM key (same as encrypt side).
|
|
284
|
+
* @param nonce - 12-byte nonce that was used at encrypt time.
|
|
285
|
+
* @param tag - 16-byte GCM authentication tag.
|
|
286
|
+
* @param aad - Optional Additional Authenticated Data. MUST exactly
|
|
287
|
+
* match the AAD passed to {@link encryptBody}; mismatch (including
|
|
288
|
+
* AAD/no-AAD asymmetry) fails the tag check and throws
|
|
289
|
+
* `crypto_decrypt_failed`.
|
|
290
|
+
* @returns The decrypted plaintext as raw bytes. If the original
|
|
291
|
+
* plaintext was a UTF-8 string, the caller can recover it via
|
|
292
|
+
* `Buffer.from(plaintext).toString('utf8')`.
|
|
293
|
+
* @throws {DeliveryCryptoError} `crypto_decrypt_failed` on any of:
|
|
294
|
+
* malformed lengths, wrong session key, tampered ciphertext / tag /
|
|
295
|
+
* nonce, AAD mismatch, malformed AAD type, or underlying
|
|
296
|
+
* `node:crypto` failure.
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* const aad = new Uint8Array(52);
|
|
301
|
+
* aad.set(bytesFromHex(txId), 0);
|
|
302
|
+
* aad.set(bytesFromHex(signerAddress), 32);
|
|
303
|
+
* const plaintextBytes = decryptBody(ciphertext, key, nonce, tag, aad);
|
|
304
|
+
* const json = Buffer.from(plaintextBytes).toString('utf8');
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
function decryptBody(ciphertext, sessionKey, nonce, tag, aad) {
|
|
308
|
+
// ── Validate all four inputs up-front ───────────────────────────
|
|
309
|
+
if (!(ciphertext instanceof Uint8Array)) {
|
|
310
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', `ciphertext must be a Uint8Array, got ${typeof ciphertext}`, { field: 'ciphertext', type: typeof ciphertext });
|
|
311
|
+
}
|
|
312
|
+
if (!(sessionKey instanceof Uint8Array) || sessionKey.length !== exports.AES_KEY_LENGTH) {
|
|
313
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', `sessionKey must be a Uint8Array of exactly ${exports.AES_KEY_LENGTH} bytes (got ${sessionKey instanceof Uint8Array ? sessionKey.length : typeof sessionKey})`, {
|
|
314
|
+
field: 'sessionKey',
|
|
315
|
+
expectedLength: exports.AES_KEY_LENGTH,
|
|
316
|
+
actualLength: sessionKey instanceof Uint8Array ? sessionKey.length : null,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if (!(nonce instanceof Uint8Array) || nonce.length !== exports.AES_GCM_NONCE_LENGTH) {
|
|
320
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', `nonce must be a Uint8Array of exactly ${exports.AES_GCM_NONCE_LENGTH} bytes (got ${nonce instanceof Uint8Array ? nonce.length : typeof nonce})`, {
|
|
321
|
+
field: 'nonce',
|
|
322
|
+
expectedLength: exports.AES_GCM_NONCE_LENGTH,
|
|
323
|
+
actualLength: nonce instanceof Uint8Array ? nonce.length : null,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
if (!(tag instanceof Uint8Array) || tag.length !== exports.AES_GCM_TAG_LENGTH) {
|
|
327
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', `tag must be a Uint8Array of exactly ${exports.AES_GCM_TAG_LENGTH} bytes (got ${tag instanceof Uint8Array ? tag.length : typeof tag})`, {
|
|
328
|
+
field: 'tag',
|
|
329
|
+
expectedLength: exports.AES_GCM_TAG_LENGTH,
|
|
330
|
+
actualLength: tag instanceof Uint8Array ? tag.length : null,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
if (aad !== undefined && !(aad instanceof Uint8Array)) {
|
|
334
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', `aad must be a Uint8Array when supplied, got ${typeof aad}`, { field: 'aad', type: typeof aad });
|
|
335
|
+
}
|
|
336
|
+
// ── Decrypt ─────────────────────────────────────────────────────
|
|
337
|
+
try {
|
|
338
|
+
const decipher = (0, node_crypto_1.createDecipheriv)('aes-256-gcm', sessionKey, nonce, {
|
|
339
|
+
authTagLength: exports.AES_GCM_TAG_LENGTH,
|
|
340
|
+
});
|
|
341
|
+
decipher.setAuthTag(tag);
|
|
342
|
+
// H5 binding: AAD MUST be supplied to setAAD before any ciphertext
|
|
343
|
+
// is fed in (node:crypto / OpenSSL contract). If the encrypt side
|
|
344
|
+
// used AAD and we omit it here, the tag will fail to verify in
|
|
345
|
+
// `final()`. If the encrypt side used no AAD and we supply one
|
|
346
|
+
// here, same outcome — symmetric failure, fail-closed.
|
|
347
|
+
if (aad !== undefined) {
|
|
348
|
+
decipher.setAAD(aad);
|
|
349
|
+
}
|
|
350
|
+
const part1 = decipher.update(ciphertext);
|
|
351
|
+
// `final()` throws if the GCM tag doesn't authenticate. This is
|
|
352
|
+
// the integrity check; anything that reaches the assignment
|
|
353
|
+
// below has been authenticated under (sessionKey, nonce, tag).
|
|
354
|
+
const part2 = decipher.final();
|
|
355
|
+
const combined = Buffer.concat([part1, part2]);
|
|
356
|
+
return new Uint8Array(combined.buffer, combined.byteOffset, combined.byteLength);
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', `AES-256-GCM decryption / authentication failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err.message : String(err) });
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
exports.decryptBody = decryptBody;
|
|
363
|
+
// ============================================================================
|
|
364
|
+
// Public API: keccak256 body hash
|
|
365
|
+
// ============================================================================
|
|
366
|
+
/**
|
|
367
|
+
* Compute the keccak256 hash of an envelope body, in the exact form
|
|
368
|
+
* embedded into the `payloadHash` field of the signed EIP-712
|
|
369
|
+
* projection.
|
|
370
|
+
*
|
|
371
|
+
* Per AIP-16 Rev 5 §6.2, `payloadHash = keccak256(bodyBytes)` where
|
|
372
|
+
* `bodyBytes` is:
|
|
373
|
+
* - For `scheme: "public-v1"`: the UTF-8 bytes of the plaintext body
|
|
374
|
+
* string (or the raw `Uint8Array` if the caller pre-encoded).
|
|
375
|
+
* - For `scheme: "x25519-aes256gcm-v1"`: the *ciphertext* bytes (the
|
|
376
|
+
* output of {@link encryptBody}.ciphertext), not the plaintext.
|
|
377
|
+
* This commits the signer to the exact bytes that travel on the
|
|
378
|
+
* wire, preventing a malicious relay from substituting alternative
|
|
379
|
+
* ciphertext with the same plaintext (which GCM nonces would
|
|
380
|
+
* actually preclude, but the EIP-712 commitment is independent of
|
|
381
|
+
* that).
|
|
382
|
+
*
|
|
383
|
+
* The output is a 0x-prefixed lowercase 66-char hex string (32-byte
|
|
384
|
+
* keccak256 digest), exactly matching the `bytes32` field shape in
|
|
385
|
+
* the EIP-712 types.
|
|
386
|
+
*
|
|
387
|
+
* @param body - The bytes to hash. A `string` is interpreted as UTF-8.
|
|
388
|
+
* @returns The keccak256 digest as `0x` + 64 lowercase hex chars.
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```typescript
|
|
392
|
+
* // Public scheme:
|
|
393
|
+
* const h1 = bodyHash('{"result":"ok"}');
|
|
394
|
+
*
|
|
395
|
+
* // Encrypted scheme — hash the CIPHERTEXT, not the plaintext:
|
|
396
|
+
* const { ciphertext } = encryptBody(plaintext, key);
|
|
397
|
+
* const h2 = bodyHash(ciphertext);
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
function bodyHash(body) {
|
|
401
|
+
const bytes = toBytes(body, 'body');
|
|
402
|
+
// ethers.keccak256 accepts `BytesLike`; a Uint8Array is one of the
|
|
403
|
+
// accepted forms. The return value is already a 0x-prefixed
|
|
404
|
+
// lowercase hex string of length 66.
|
|
405
|
+
const digest = ethers_1.ethers.keccak256(bytes);
|
|
406
|
+
return digest;
|
|
407
|
+
}
|
|
408
|
+
exports.bodyHash = bodyHash;
|
|
409
|
+
// ============================================================================
|
|
410
|
+
// Public API: Hex format helpers
|
|
411
|
+
// ============================================================================
|
|
412
|
+
/**
|
|
413
|
+
* Encode raw bytes to a lowercase 0x-prefixed hex string.
|
|
414
|
+
*
|
|
415
|
+
* Intentionally byte-for-byte equivalent to the equivalent helper in
|
|
416
|
+
* `./keys.ts` (which is `internal` there). Exposed here at the
|
|
417
|
+
* module surface so envelope-builder callers can serialize their
|
|
418
|
+
* ciphertext / nonce / tag without reaching into `./keys.ts` internals.
|
|
419
|
+
*
|
|
420
|
+
* Hand-rolled rather than `Buffer.from(b).toString('hex')` so the
|
|
421
|
+
* implementation is portable to non-Node runtimes (Bun, web) without
|
|
422
|
+
* polyfills, and to avoid Buffer-vs-Uint8Array subclass confusion.
|
|
423
|
+
*
|
|
424
|
+
* @param b - Raw bytes to encode.
|
|
425
|
+
* @returns A `0x`-prefixed lowercase hex string of length
|
|
426
|
+
* `2 + 2 * b.length`.
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```typescript
|
|
430
|
+
* bytesToHex(new Uint8Array([0xab, 0xcd])); // "0xabcd"
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
function bytesToHex(b) {
|
|
434
|
+
if (!(b instanceof Uint8Array)) {
|
|
435
|
+
throw new keys_1.DeliveryCryptoError('crypto_encrypt_failed', `bytesToHex expected Uint8Array, got ${typeof b}`, { type: typeof b });
|
|
436
|
+
}
|
|
437
|
+
let out = '0x';
|
|
438
|
+
for (let i = 0; i < b.length; i++) {
|
|
439
|
+
const byte = b[i];
|
|
440
|
+
out += HEX_CHARS[(byte >>> 4) & 0x0f];
|
|
441
|
+
out += HEX_CHARS[byte & 0x0f];
|
|
442
|
+
}
|
|
443
|
+
return out;
|
|
444
|
+
}
|
|
445
|
+
exports.bytesToHex = bytesToHex;
|
|
446
|
+
/**
|
|
447
|
+
* Decode a 0x-prefixed hex string to raw bytes.
|
|
448
|
+
*
|
|
449
|
+
* Strict on shape: the string MUST start with `0x` (case-insensitive
|
|
450
|
+
* prefix), MUST contain only hex digits after the prefix, and MUST
|
|
451
|
+
* have an even number of hex digits. Returns a fresh `Uint8Array`.
|
|
452
|
+
*
|
|
453
|
+
* Used at the wire boundary to decode `bodyCiphertextHex`, `nonceHex`,
|
|
454
|
+
* `tagHex`, and any other hex-serialized byte field into the byte
|
|
455
|
+
* forms expected by {@link decryptBody}.
|
|
456
|
+
*
|
|
457
|
+
* @param hex - 0x-prefixed hex string, even number of hex digits.
|
|
458
|
+
* @returns A fresh `Uint8Array` of length `(hex.length - 2) / 2`.
|
|
459
|
+
* @throws {DeliveryCryptoError} `crypto_decrypt_failed` if `hex` is
|
|
460
|
+
* missing the `0x` prefix, has odd length, or contains non-hex
|
|
461
|
+
* characters. (`crypto_decrypt_failed` is the most likely site of
|
|
462
|
+
* failure for this helper; encrypt-side callers will instead get
|
|
463
|
+
* the structural validation in {@link encryptBody}.)
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```typescript
|
|
467
|
+
* bytesFromHex('0xabcd'); // Uint8Array(2) [0xab, 0xcd]
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
function bytesFromHex(hex) {
|
|
471
|
+
if (typeof hex !== 'string') {
|
|
472
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', `bytesFromHex expected string, got ${typeof hex}`, { type: typeof hex });
|
|
473
|
+
}
|
|
474
|
+
if (hex.length < 2 ||
|
|
475
|
+
hex[0] !== '0' ||
|
|
476
|
+
(hex[1] !== 'x' && hex[1] !== 'X')) {
|
|
477
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', 'bytesFromHex requires a 0x-prefixed string', { prefix: hex.slice(0, 4) });
|
|
478
|
+
}
|
|
479
|
+
const body = hex.slice(2);
|
|
480
|
+
if (body.length % 2 !== 0) {
|
|
481
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', `bytesFromHex requires an even number of hex digits (got ${body.length})`, { hexChars: body.length });
|
|
482
|
+
}
|
|
483
|
+
if (!/^[0-9a-fA-F]*$/.test(body)) {
|
|
484
|
+
throw new keys_1.DeliveryCryptoError('crypto_decrypt_failed', 'bytesFromHex received non-hex characters after the 0x prefix', {});
|
|
485
|
+
}
|
|
486
|
+
const out = new Uint8Array(body.length / 2);
|
|
487
|
+
for (let i = 0; i < out.length; i++) {
|
|
488
|
+
const hi = parseInt(body[i * 2], 16);
|
|
489
|
+
const lo = parseInt(body[i * 2 + 1], 16);
|
|
490
|
+
out[i] = (hi << 4) | lo;
|
|
491
|
+
}
|
|
492
|
+
return out;
|
|
493
|
+
}
|
|
494
|
+
exports.bytesFromHex = bytesFromHex;
|
|
495
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/delivery/crypto.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgFG;;;AAEH,6CAA4E;AAE5E,mCAAgC;AAEhC,iCAA0E;AAE1E,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E;;;;;;;;;;;;GAYG;AACU,QAAA,oBAAoB,GAAG,EAAW,CAAC;AAEhD;;;;;;;GAOG;AACU,QAAA,kBAAkB,GAAG,EAAW,CAAC;AAE9C;;;;GAIG;AACU,QAAA,cAAc,GAAG,kCAA2B,CAAC;AA0C1D,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;;;;;;GAOG;AACH,SAAS,OAAO,CAAC,KAA0B,EAAE,KAAa;IACxD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,GAAG,KAAK,wCAAwC,OAAO,KAAK,EAAE,EAC9D,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,KAAK,EAAE,CAC9B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,SAAS,GAAG,kBAAkB,CAAC;AAErC,+EAA+E;AAC/E,0BAA0B;AAC1B,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,SAAgB,WAAW,CACzB,SAA8B,EAC9B,UAAsB,EACtB,GAAgB;IAEhB,mEAAmE;IACnE,IAAI,CAAC,CAAC,UAAU,YAAY,UAAU,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,wCAAwC,OAAO,UAAU,EAAE,EAC3D,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,UAAU,EAAE,CACjD,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,sBAAc,EAAE,CAAC;QACzC,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,8BAA8B,sBAAc,eAAe,UAAU,CAAC,MAAM,GAAG,EAC/E;YACE,KAAK,EAAE,YAAY;YACnB,cAAc,EAAE,sBAAc;YAC9B,YAAY,EAAE,UAAU,CAAC,MAAM;SAChC,CACF,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,EAAE;IACF,6DAA6D;IAC7D,gEAAgE;IAChE,iEAAiE;IACjE,mEAAmE;IACnE,yBAAyB;IACzB,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,YAAY,UAAU,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,+CAA+C,OAAO,GAAG,EAAE,EAC3D,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,GAAG,EAAE,CACnC,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAEhD,mEAAmE;IACnE,IAAI,KAAiB,CAAC;IACtB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,UAAU,CAAC,IAAA,yBAAW,EAAC,4BAAoB,CAAC,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,eAAe,4BAAoB,aACjC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,EACF,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC5D,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,IAAI,UAAsB,CAAC;IAC3B,IAAI,GAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,4BAAc,EAAC,aAAa,EAAE,UAAU,EAAE,KAAK,EAAE;YAC9D,aAAa,EAAE,0BAAkB;SAClC,CAAC,CAAC;QACH,gEAAgE;QAChE,8DAA8D;QAC9D,kEAAkE;QAClE,gEAAgE;QAChE,6DAA6D;QAC7D,uCAAuC;QACvC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;QAC7B,gEAAgE;QAChE,iEAAiE;QACjE,gEAAgE;QAChE,+DAA+D;QAC/D,oBAAoB;QACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/C,UAAU,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QACvF,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACnC,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,kCACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,EACF,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC5D,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,IAAI,GAAG,CAAC,MAAM,KAAK,0BAAkB,EAAE,CAAC;QACtC,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,iDAAiD,GAAG,CAAC,MAAM,EAAE,EAC7D,EAAE,cAAc,EAAE,0BAAkB,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,CACjE,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,4BAAoB,EAAE,CAAC;QAC1C,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,oCAAoC,KAAK,CAAC,MAAM,EAAE,EAClD,EAAE,cAAc,EAAE,4BAAoB,EAAE,YAAY,EAAE,KAAK,CAAC,MAAM,EAAE,CACrE,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACpC,CAAC;AA/GD,kCA+GC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,SAAgB,WAAW,CACzB,UAAsB,EACtB,UAAsB,EACtB,KAAiB,EACjB,GAAe,EACf,GAAgB;IAEhB,mEAAmE;IACnE,IAAI,CAAC,CAAC,UAAU,YAAY,UAAU,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,wCAAwC,OAAO,UAAU,EAAE,EAC3D,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,UAAU,EAAE,CACjD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,CAAC,UAAU,YAAY,UAAU,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,sBAAc,EAAE,CAAC;QAChF,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,8CAA8C,sBAAc,eAC1D,UAAU,YAAY,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,UAChE,GAAG,EACH;YACE,KAAK,EAAE,YAAY;YACnB,cAAc,EAAE,sBAAc;YAC9B,YAAY,EAAE,UAAU,YAAY,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;SAC1E,CACF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,4BAAoB,EAAE,CAAC;QAC5E,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,yCAAyC,4BAAoB,eAC3D,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,KACtD,GAAG,EACH;YACE,KAAK,EAAE,OAAO;YACd,cAAc,EAAE,4BAAoB;YACpC,YAAY,EAAE,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;SAChE,CACF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,CAAC,GAAG,YAAY,UAAU,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,0BAAkB,EAAE,CAAC;QACtE,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,uCAAuC,0BAAkB,eACvD,GAAG,YAAY,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,GAClD,GAAG,EACH;YACE,KAAK,EAAE,KAAK;YACZ,cAAc,EAAE,0BAAkB;YAClC,YAAY,EAAE,GAAG,YAAY,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;SAC5D,CACF,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,YAAY,UAAU,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,+CAA+C,OAAO,GAAG,EAAE,EAC3D,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,GAAG,EAAE,CACnC,CAAC;IACJ,CAAC;IAED,mEAAmE;IACnE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAA,8BAAgB,EAAC,aAAa,EAAE,UAAU,EAAE,KAAK,EAAE;YAClE,aAAa,EAAE,0BAAkB;SAClC,CAAC,CAAC;QACH,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACzB,mEAAmE;QACnE,kEAAkE;QAClE,+DAA+D;QAC/D,+DAA+D;QAC/D,uDAAuD;QACvD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC1C,gEAAgE;QAChE,4DAA4D;QAC5D,+DAA+D;QAC/D,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/C,OAAO,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IACnF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,mDACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,EACF,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC5D,CAAC;IACJ,CAAC;AACH,CAAC;AA5FD,kCA4FC;AAED,+EAA+E;AAC/E,kCAAkC;AAClC,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,SAAgB,QAAQ,CAAC,IAAyB;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,mEAAmE;IACnE,4DAA4D;IAC5D,qCAAqC;IACrC,MAAM,MAAM,GAAG,eAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,MAAuB,CAAC;AACjC,CAAC;AAPD,4BAOC;AAED,+EAA+E;AAC/E,iCAAiC;AACjC,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAgB,UAAU,CAAC,CAAa;IACtC,IAAI,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,uCAAuC,OAAO,CAAC,EAAE,EACjD,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CACnB,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAW,CAAC;QAC5B,GAAG,IAAI,SAAS,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACtC,GAAG,IAAI,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,GAAoB,CAAC;AAC9B,CAAC;AAfD,gCAeC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAgB,YAAY,CAAC,GAAW;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,qCAAqC,OAAO,GAAG,EAAE,EACjD,EAAE,IAAI,EAAE,OAAO,GAAG,EAAE,CACrB,CAAC;IACJ,CAAC;IACD,IACE,GAAG,CAAC,MAAM,GAAG,CAAC;QACd,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG;QACd,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,EAClC,CAAC;QACD,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,4CAA4C,EAC5C,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAC5B,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,2DAA2D,IAAI,CAAC,MAAM,GAAG,EACzE,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,CAC1B,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,0BAAmB,CAC3B,uBAAuB,EACvB,8DAA8D,EAC9D,EAAE,CACH,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAW,EAAE,EAAE,CAAC,CAAC;QACnD,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAzCD,oCAyCC"}
|