@bcts/components 1.0.0-alpha.5
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/LICENSE +48 -0
- package/README.md +14 -0
- package/dist/digest--g2P5w95.mjs +459 -0
- package/dist/digest--g2P5w95.mjs.map +1 -0
- package/dist/digest-BquQoTdd.cjs +507 -0
- package/dist/digest-BquQoTdd.cjs.map +1 -0
- package/dist/digest-D5KUIzcO.mjs +3 -0
- package/dist/digest-Wqhb0Fzf.cjs +3 -0
- package/dist/index.cjs +10237 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +5369 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +5369 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.iife.js +10768 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.mjs +10057 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Copyright © 2023 Blockchain Commons, LLC
|
|
2
|
+
Copyright © 2025 Leonardo Amoroso Custodio
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
5
|
+
are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
8
|
+
this list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
Subject to the terms and conditions of this license, each copyright holder and
|
|
15
|
+
contributor hereby grants to those receiving rights under this license a
|
|
16
|
+
perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
17
|
+
(except for failure to satisfy the conditions of this license) patent license to
|
|
18
|
+
make, have made, use, offer to sell, sell, import, and otherwise transfer this
|
|
19
|
+
software, where such license applies only to those patent claims, already
|
|
20
|
+
acquired or hereafter acquired, licensable by such copyright holder or
|
|
21
|
+
contributor that are necessarily infringed by:
|
|
22
|
+
|
|
23
|
+
(a) their Contribution(s) (the licensed copyrights of copyright holders and
|
|
24
|
+
non-copyrightable additions of contributors, in source or binary form)
|
|
25
|
+
alone; or
|
|
26
|
+
|
|
27
|
+
(b) combination of their Contribution(s) with the work of authorship to
|
|
28
|
+
which such Contribution(s) was added by such copyright holder or
|
|
29
|
+
contributor, if, at the time the Contribution is added, such addition causes
|
|
30
|
+
such combination to be necessarily infringed. The patent license shall not
|
|
31
|
+
apply to any other combinations which include the Contribution.
|
|
32
|
+
|
|
33
|
+
Except as expressly stated above, no rights or licenses from any copyright
|
|
34
|
+
holder or contributor is granted under this license, whether expressly, by
|
|
35
|
+
implication, estoppel or otherwise.
|
|
36
|
+
|
|
37
|
+
DISCLAIMER
|
|
38
|
+
|
|
39
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
40
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
41
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
42
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
|
|
43
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
44
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
45
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
46
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
47
|
+
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
48
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Blockchain Commons Secure Components for TypeScript
|
|
2
|
+
|
|
3
|
+
> Disclaimer: This package is under active development and APIs may change.
|
|
4
|
+
|
|
5
|
+
## Introduction
|
|
6
|
+
|
|
7
|
+
A collection of useful primitives for cryptography, semantic graphs, and cryptocurrency, primarily for use in higher-level [Blockchain Commons](https://blockchaincommons.com) projects. All the types are [CBOR](https://cbor.io) serializable, and a number of them can also be serialized to and from [URs](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md).
|
|
8
|
+
|
|
9
|
+
Also includes a library of CBOR tags and UR types for use with these types.
|
|
10
|
+
|
|
11
|
+
## Rust Reference Implementation
|
|
12
|
+
|
|
13
|
+
This TypeScript implementation is based on [bc-components-rust](https://github.com/BlockchainCommons/bc-components-rust) **v0.30.0** ([commit](https://github.com/BlockchainCommons/bc-components-rust/tree/f3d0081db048da942f316aa4cb5128af8921edd8)).
|
|
14
|
+
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { CryptoError, SHA256_SIZE, sha256 } from "@bcts/crypto";
|
|
2
|
+
import { createTaggedCbor, decodeCbor, expectBytes, extractTaggedContent, tagsForValues, toByteString, validateTag } from "@bcts/dcbor";
|
|
3
|
+
import { DIGEST } from "@bcts/tags";
|
|
4
|
+
import { UR } from "@bcts/uniform-resources";
|
|
5
|
+
|
|
6
|
+
//#region src/error.ts
|
|
7
|
+
/**
|
|
8
|
+
* Error types re-exported from @bcts/crypto
|
|
9
|
+
* with additional factory methods for components
|
|
10
|
+
*
|
|
11
|
+
* Ported from bc-components-rust/src/error.rs
|
|
12
|
+
*/
|
|
13
|
+
var CryptoError$1 = class CryptoError$1 extends CryptoError {
|
|
14
|
+
static invalidSize(expected, actual) {
|
|
15
|
+
return new CryptoError$1(`Invalid size: expected ${expected}, got ${actual}`);
|
|
16
|
+
}
|
|
17
|
+
static invalidFormat(message) {
|
|
18
|
+
return new CryptoError$1(`Invalid format: ${message}`);
|
|
19
|
+
}
|
|
20
|
+
static cryptoOperation(message) {
|
|
21
|
+
return new CryptoError$1(`Crypto operation failed: ${message}`);
|
|
22
|
+
}
|
|
23
|
+
static invalidInput(message) {
|
|
24
|
+
return new CryptoError$1(`Invalid input: ${message}`);
|
|
25
|
+
}
|
|
26
|
+
static dataTooShort(name, minSize, actual) {
|
|
27
|
+
return new CryptoError$1(`${name} too short: minimum ${minSize}, got ${actual}`);
|
|
28
|
+
}
|
|
29
|
+
static invalidData(message) {
|
|
30
|
+
return new CryptoError$1(`Invalid data: ${message}`);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function isError(result) {
|
|
34
|
+
return result instanceof Error;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/utils.ts
|
|
39
|
+
/**
|
|
40
|
+
* Utility functions for byte array conversions and comparisons.
|
|
41
|
+
*
|
|
42
|
+
* These functions provide cross-platform support for common byte manipulation
|
|
43
|
+
* operations needed in cryptographic and encoding contexts.
|
|
44
|
+
*
|
|
45
|
+
* @packageDocumentation
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* Convert a Uint8Array to a lowercase hexadecimal string.
|
|
49
|
+
*
|
|
50
|
+
* @param data - The byte array to convert
|
|
51
|
+
* @returns A lowercase hex string representation (2 characters per byte)
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);
|
|
56
|
+
* bytesToHex(bytes); // "deadbeef"
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
function bytesToHex(data) {
|
|
60
|
+
return Array.from(data).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Convert a hexadecimal string to a Uint8Array.
|
|
64
|
+
*
|
|
65
|
+
* @param hex - A hex string (must have even length, case-insensitive)
|
|
66
|
+
* @returns The decoded byte array
|
|
67
|
+
* @throws {Error} If the hex string has odd length or contains invalid characters
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```typescript
|
|
71
|
+
* hexToBytes("deadbeef"); // Uint8Array([0xde, 0xad, 0xbe, 0xef])
|
|
72
|
+
* hexToBytes("DEADBEEF"); // Uint8Array([0xde, 0xad, 0xbe, 0xef])
|
|
73
|
+
* hexToBytes("xyz"); // throws Error: Invalid hex string
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function hexToBytes(hex) {
|
|
77
|
+
if (hex.length % 2 !== 0) throw new Error(`Hex string must have even length, got ${hex.length}`);
|
|
78
|
+
if (!/^[0-9A-Fa-f]*$/.test(hex)) throw new Error("Invalid hex string: contains non-hexadecimal characters");
|
|
79
|
+
const data = new Uint8Array(hex.length / 2);
|
|
80
|
+
for (let i = 0; i < hex.length; i += 2) data[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
81
|
+
return data;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Convert a Uint8Array to a base64-encoded string.
|
|
85
|
+
*
|
|
86
|
+
* This function works in both browser and Node.js environments.
|
|
87
|
+
* Uses btoa which is available in browsers and Node.js 16+.
|
|
88
|
+
*
|
|
89
|
+
* @param data - The byte array to encode
|
|
90
|
+
* @returns A base64-encoded string
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const bytes = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
|
|
95
|
+
* toBase64(bytes); // "SGVsbG8="
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
function toBase64(data) {
|
|
99
|
+
let binary = "";
|
|
100
|
+
for (const byte of data) binary += String.fromCharCode(byte);
|
|
101
|
+
return btoa(binary);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Convert a base64-encoded string to a Uint8Array.
|
|
105
|
+
*
|
|
106
|
+
* This function works in both browser and Node.js environments.
|
|
107
|
+
* Uses atob which is available in browsers and Node.js 16+.
|
|
108
|
+
*
|
|
109
|
+
* @param base64 - A base64-encoded string
|
|
110
|
+
* @returns The decoded byte array
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* fromBase64("SGVsbG8="); // Uint8Array([72, 101, 108, 108, 111])
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
function fromBase64(base64) {
|
|
118
|
+
const binary = atob(base64);
|
|
119
|
+
const bytes = new Uint8Array(binary.length);
|
|
120
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
121
|
+
return bytes;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Compare two Uint8Arrays for equality using constant-time comparison.
|
|
125
|
+
*
|
|
126
|
+
* This function is designed to be resistant to timing attacks by always
|
|
127
|
+
* comparing all bytes regardless of where a difference is found. The
|
|
128
|
+
* comparison time depends only on the length of the arrays, not on where
|
|
129
|
+
* they differ.
|
|
130
|
+
*
|
|
131
|
+
* **Security Note**: If the arrays have different lengths, this function
|
|
132
|
+
* returns `false` immediately, which does leak length information. For
|
|
133
|
+
* cryptographic uses where length should also be secret, ensure both
|
|
134
|
+
* arrays are the same length before comparison.
|
|
135
|
+
*
|
|
136
|
+
* @param a - First byte array
|
|
137
|
+
* @param b - Second byte array
|
|
138
|
+
* @returns `true` if both arrays have the same length and identical contents
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* const key1 = new Uint8Array([1, 2, 3, 4]);
|
|
143
|
+
* const key2 = new Uint8Array([1, 2, 3, 4]);
|
|
144
|
+
* const key3 = new Uint8Array([1, 2, 3, 5]);
|
|
145
|
+
*
|
|
146
|
+
* bytesEqual(key1, key2); // true
|
|
147
|
+
* bytesEqual(key1, key3); // false
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
function bytesEqual(a, b) {
|
|
151
|
+
if (a.length !== b.length) return false;
|
|
152
|
+
let result = 0;
|
|
153
|
+
for (let i = 0; i < a.length; i++) result |= a[i] ^ b[i];
|
|
154
|
+
return result === 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/digest.ts
|
|
159
|
+
/**
|
|
160
|
+
* SHA-256 cryptographic digest (32 bytes)
|
|
161
|
+
*
|
|
162
|
+
* Ported from bc-components-rust/src/digest.rs
|
|
163
|
+
*
|
|
164
|
+
* A `Digest` represents the cryptographic hash of some data. In this
|
|
165
|
+
* implementation, SHA-256 is used, which produces a 32-byte hash value.
|
|
166
|
+
* Digests are used throughout the crate for data verification and as unique
|
|
167
|
+
* identifiers derived from data.
|
|
168
|
+
*
|
|
169
|
+
* # CBOR Serialization
|
|
170
|
+
*
|
|
171
|
+
* `Digest` implements the CBOR tagged encoding interfaces, which means it can be
|
|
172
|
+
* serialized to and deserialized from CBOR with a specific tag (TAG_DIGEST = 40001).
|
|
173
|
+
*
|
|
174
|
+
* # UR Serialization
|
|
175
|
+
*
|
|
176
|
+
* When serialized as a Uniform Resource (UR), a `Digest` is represented as a
|
|
177
|
+
* binary blob with the type "digest".
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```typescript
|
|
181
|
+
* import { Digest } from '@bcts/components';
|
|
182
|
+
*
|
|
183
|
+
* // Create a digest from a string
|
|
184
|
+
* const data = new TextEncoder().encode("hello world");
|
|
185
|
+
* const digest = Digest.fromImage(data);
|
|
186
|
+
*
|
|
187
|
+
* // Validate that the digest matches the original data
|
|
188
|
+
* console.log(digest.validate(data)); // true
|
|
189
|
+
*
|
|
190
|
+
* // Create a digest from a hex string
|
|
191
|
+
* const hexString = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
|
|
192
|
+
* const digest2 = Digest.fromHex(hexString);
|
|
193
|
+
*
|
|
194
|
+
* // Retrieve the digest as hex
|
|
195
|
+
* console.log(digest2.hex()); // b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
var Digest = class Digest {
|
|
199
|
+
static DIGEST_SIZE = SHA256_SIZE;
|
|
200
|
+
_data;
|
|
201
|
+
constructor(data) {
|
|
202
|
+
if (data.length !== Digest.DIGEST_SIZE) throw CryptoError$1.invalidSize(Digest.DIGEST_SIZE, data.length);
|
|
203
|
+
this._data = new Uint8Array(data);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Get the digest data.
|
|
207
|
+
*/
|
|
208
|
+
data() {
|
|
209
|
+
return this._data;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Create a Digest from a 32-byte array.
|
|
213
|
+
*/
|
|
214
|
+
static fromData(data) {
|
|
215
|
+
return new Digest(new Uint8Array(data));
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Create a Digest from data, validating the length.
|
|
219
|
+
* Alias for fromData for compatibility with Rust API.
|
|
220
|
+
*/
|
|
221
|
+
static fromDataRef(data) {
|
|
222
|
+
return Digest.fromData(data);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Create a Digest from hex string.
|
|
226
|
+
*
|
|
227
|
+
* @throws Error if the hex string is not exactly 64 characters.
|
|
228
|
+
*/
|
|
229
|
+
static fromHex(hex) {
|
|
230
|
+
return new Digest(hexToBytes(hex));
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Compute SHA-256 digest of data (called "image" in Rust).
|
|
234
|
+
*
|
|
235
|
+
* @param image - The data to hash
|
|
236
|
+
*/
|
|
237
|
+
static fromImage(image) {
|
|
238
|
+
const hashData = sha256(image);
|
|
239
|
+
return new Digest(new Uint8Array(hashData));
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Compute SHA-256 digest from multiple data parts.
|
|
243
|
+
*
|
|
244
|
+
* The parts are concatenated and then hashed.
|
|
245
|
+
*
|
|
246
|
+
* @param imageParts - Array of byte arrays to concatenate and hash
|
|
247
|
+
*/
|
|
248
|
+
static fromImageParts(imageParts) {
|
|
249
|
+
const totalLength = imageParts.reduce((sum, part) => sum + part.length, 0);
|
|
250
|
+
const buf = new Uint8Array(totalLength);
|
|
251
|
+
let offset = 0;
|
|
252
|
+
for (const part of imageParts) {
|
|
253
|
+
buf.set(part, offset);
|
|
254
|
+
offset += part.length;
|
|
255
|
+
}
|
|
256
|
+
return Digest.fromImage(buf);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Compute SHA-256 digest from an array of Digests.
|
|
260
|
+
*
|
|
261
|
+
* The digest bytes are concatenated and then hashed.
|
|
262
|
+
*
|
|
263
|
+
* @param digests - Array of Digests to combine
|
|
264
|
+
*/
|
|
265
|
+
static fromDigests(digests) {
|
|
266
|
+
const buf = new Uint8Array(digests.length * Digest.DIGEST_SIZE);
|
|
267
|
+
let offset = 0;
|
|
268
|
+
for (const digest of digests) {
|
|
269
|
+
buf.set(digest._data, offset);
|
|
270
|
+
offset += Digest.DIGEST_SIZE;
|
|
271
|
+
}
|
|
272
|
+
return Digest.fromImage(buf);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Compute SHA-256 digest of data (legacy alias for fromImage).
|
|
276
|
+
* @deprecated Use fromImage instead
|
|
277
|
+
*/
|
|
278
|
+
static hash(data) {
|
|
279
|
+
return Digest.fromImage(data);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get the raw digest bytes as a copy.
|
|
283
|
+
*/
|
|
284
|
+
toData() {
|
|
285
|
+
return new Uint8Array(this._data);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get a reference to the raw digest bytes.
|
|
289
|
+
*/
|
|
290
|
+
asBytes() {
|
|
291
|
+
return this._data;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Get hex string representation.
|
|
295
|
+
*/
|
|
296
|
+
hex() {
|
|
297
|
+
return bytesToHex(this._data);
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Get hex string representation (alias for hex()).
|
|
301
|
+
*/
|
|
302
|
+
toHex() {
|
|
303
|
+
return this.hex();
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Get base64 representation.
|
|
307
|
+
*/
|
|
308
|
+
toBase64() {
|
|
309
|
+
return toBase64(this._data);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get the first four bytes of the digest as a hexadecimal string.
|
|
313
|
+
* Useful for short descriptions.
|
|
314
|
+
*/
|
|
315
|
+
shortDescription() {
|
|
316
|
+
return bytesToHex(this._data.slice(0, 4));
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Validate the digest against the given image.
|
|
320
|
+
*
|
|
321
|
+
* The image is hashed with SHA-256 and compared to this digest.
|
|
322
|
+
* @returns `true` if the digest matches the image.
|
|
323
|
+
*/
|
|
324
|
+
validate(image) {
|
|
325
|
+
return this.equals(Digest.fromImage(image));
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Compare with another Digest.
|
|
329
|
+
*/
|
|
330
|
+
equals(other) {
|
|
331
|
+
if (this._data.length !== other._data.length) return false;
|
|
332
|
+
for (let i = 0; i < this._data.length; i++) if (this._data[i] !== other._data[i]) return false;
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Compare digests lexicographically.
|
|
337
|
+
*/
|
|
338
|
+
compare(other) {
|
|
339
|
+
for (let i = 0; i < this._data.length; i++) {
|
|
340
|
+
const a = this._data[i];
|
|
341
|
+
const b = other._data[i];
|
|
342
|
+
if (a < b) return -1;
|
|
343
|
+
if (a > b) return 1;
|
|
344
|
+
}
|
|
345
|
+
return 0;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Get string representation.
|
|
349
|
+
*/
|
|
350
|
+
toString() {
|
|
351
|
+
return `Digest(${this.hex()})`;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* A Digest is its own digest provider - returns itself.
|
|
355
|
+
*/
|
|
356
|
+
digest() {
|
|
357
|
+
return this;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Returns the CBOR tags associated with Digest.
|
|
361
|
+
*/
|
|
362
|
+
cborTags() {
|
|
363
|
+
return tagsForValues([DIGEST.value]);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Returns the untagged CBOR encoding (as a byte string).
|
|
367
|
+
*/
|
|
368
|
+
untaggedCbor() {
|
|
369
|
+
return toByteString(this._data);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Returns the tagged CBOR encoding.
|
|
373
|
+
*/
|
|
374
|
+
taggedCbor() {
|
|
375
|
+
return createTaggedCbor(this);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Returns the tagged value in CBOR binary representation.
|
|
379
|
+
*/
|
|
380
|
+
taggedCborData() {
|
|
381
|
+
return this.taggedCbor().toData();
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Creates a Digest by decoding it from untagged CBOR.
|
|
385
|
+
*/
|
|
386
|
+
fromUntaggedCbor(cbor$1) {
|
|
387
|
+
const data = expectBytes(cbor$1);
|
|
388
|
+
return Digest.fromData(data);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Creates a Digest by decoding it from tagged CBOR.
|
|
392
|
+
*/
|
|
393
|
+
fromTaggedCbor(cbor$1) {
|
|
394
|
+
validateTag(cbor$1, this.cborTags());
|
|
395
|
+
const content = extractTaggedContent(cbor$1);
|
|
396
|
+
return this.fromUntaggedCbor(content);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Static method to decode from tagged CBOR.
|
|
400
|
+
*/
|
|
401
|
+
static fromTaggedCbor(cbor$1) {
|
|
402
|
+
return new Digest(new Uint8Array(Digest.DIGEST_SIZE)).fromTaggedCbor(cbor$1);
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Static method to decode from tagged CBOR binary data.
|
|
406
|
+
*/
|
|
407
|
+
static fromTaggedCborData(data) {
|
|
408
|
+
const cbor$1 = decodeCbor(data);
|
|
409
|
+
return Digest.fromTaggedCbor(cbor$1);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Static method to decode from untagged CBOR binary data.
|
|
413
|
+
*/
|
|
414
|
+
static fromUntaggedCborData(data) {
|
|
415
|
+
const bytes = expectBytes(decodeCbor(data));
|
|
416
|
+
return Digest.fromData(bytes);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Returns the UR representation of the Digest.
|
|
420
|
+
* Note: URs use untagged CBOR since the type is conveyed by the UR type itself.
|
|
421
|
+
*/
|
|
422
|
+
ur() {
|
|
423
|
+
return UR.new("digest", this.untaggedCbor());
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Returns the UR string representation.
|
|
427
|
+
*/
|
|
428
|
+
urString() {
|
|
429
|
+
return this.ur().string();
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Creates a Digest from a UR.
|
|
433
|
+
*/
|
|
434
|
+
static fromUR(ur) {
|
|
435
|
+
ur.checkType("digest");
|
|
436
|
+
return new Digest(new Uint8Array(Digest.DIGEST_SIZE)).fromUntaggedCbor(ur.cbor());
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Creates a Digest from a UR string.
|
|
440
|
+
*/
|
|
441
|
+
static fromURString(urString) {
|
|
442
|
+
const ur = UR.fromURString(urString);
|
|
443
|
+
return Digest.fromUR(ur);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Validate the given data against the digest, if any.
|
|
447
|
+
*
|
|
448
|
+
* Returns `true` if the digest is `undefined` or if the digest matches the
|
|
449
|
+
* image's digest. Returns `false` if the digest does not match.
|
|
450
|
+
*/
|
|
451
|
+
static validateOpt(image, digest) {
|
|
452
|
+
if (digest === void 0) return true;
|
|
453
|
+
return digest.validate(image);
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
//#endregion
|
|
458
|
+
export { hexToBytes as a, isError as c, fromBase64 as i, bytesEqual as n, toBase64 as o, bytesToHex as r, CryptoError$1 as s, Digest as t };
|
|
459
|
+
//# sourceMappingURL=digest--g2P5w95.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest--g2P5w95.mjs","names":["CryptoError","BaseCryptoError","CryptoError","TAG_DIGEST","cbor"],"sources":["../src/error.ts","../src/utils.ts","../src/digest.ts"],"sourcesContent":["/**\n * Error types re-exported from @bcts/crypto\n * with additional factory methods for components\n *\n * Ported from bc-components-rust/src/error.rs\n */\n\nimport { CryptoError as BaseCryptoError } from \"@bcts/crypto\";\n\nexport class CryptoError extends BaseCryptoError {\n static invalidSize(expected: number, actual: number): CryptoError {\n return new CryptoError(`Invalid size: expected ${expected}, got ${actual}`);\n }\n\n static invalidFormat(message: string): CryptoError {\n return new CryptoError(`Invalid format: ${message}`);\n }\n\n static cryptoOperation(message: string): CryptoError {\n return new CryptoError(`Crypto operation failed: ${message}`);\n }\n\n static invalidInput(message: string): CryptoError {\n return new CryptoError(`Invalid input: ${message}`);\n }\n\n static dataTooShort(name: string, minSize: number, actual: number): CryptoError {\n return new CryptoError(`${name} too short: minimum ${minSize}, got ${actual}`);\n }\n\n static invalidData(message: string): CryptoError {\n return new CryptoError(`Invalid data: ${message}`);\n }\n}\n\nexport type Result<T> = T | Error;\n\nexport function isError(result: unknown): result is Error {\n return result instanceof Error;\n}\n","/**\n * Utility functions for byte array conversions and comparisons.\n *\n * These functions provide cross-platform support for common byte manipulation\n * operations needed in cryptographic and encoding contexts.\n *\n * @packageDocumentation\n */\n\n/**\n * Convert a Uint8Array to a lowercase hexadecimal string.\n *\n * @param data - The byte array to convert\n * @returns A lowercase hex string representation (2 characters per byte)\n *\n * @example\n * ```typescript\n * const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);\n * bytesToHex(bytes); // \"deadbeef\"\n * ```\n */\nexport function bytesToHex(data: Uint8Array): string {\n return Array.from(data)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Convert a hexadecimal string to a Uint8Array.\n *\n * @param hex - A hex string (must have even length, case-insensitive)\n * @returns The decoded byte array\n * @throws {Error} If the hex string has odd length or contains invalid characters\n *\n * @example\n * ```typescript\n * hexToBytes(\"deadbeef\"); // Uint8Array([0xde, 0xad, 0xbe, 0xef])\n * hexToBytes(\"DEADBEEF\"); // Uint8Array([0xde, 0xad, 0xbe, 0xef])\n * hexToBytes(\"xyz\"); // throws Error: Invalid hex string\n * ```\n */\nexport function hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) {\n throw new Error(`Hex string must have even length, got ${hex.length}`);\n }\n if (!/^[0-9A-Fa-f]*$/.test(hex)) {\n throw new Error(\"Invalid hex string: contains non-hexadecimal characters\");\n }\n const data = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n data[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n }\n return data;\n}\n\n/**\n * Convert a Uint8Array to a base64-encoded string.\n *\n * This function works in both browser and Node.js environments.\n * Uses btoa which is available in browsers and Node.js 16+.\n *\n * @param data - The byte array to encode\n * @returns A base64-encoded string\n *\n * @example\n * ```typescript\n * const bytes = new Uint8Array([72, 101, 108, 108, 111]); // \"Hello\"\n * toBase64(bytes); // \"SGVsbG8=\"\n * ```\n */\nexport function toBase64(data: Uint8Array): string {\n // Convert bytes to binary string without spread operator to avoid\n // call stack limits for large arrays (spread would fail at ~65k bytes)\n let binary = \"\";\n for (const byte of data) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n}\n\n/**\n * Convert a base64-encoded string to a Uint8Array.\n *\n * This function works in both browser and Node.js environments.\n * Uses atob which is available in browsers and Node.js 16+.\n *\n * @param base64 - A base64-encoded string\n * @returns The decoded byte array\n *\n * @example\n * ```typescript\n * fromBase64(\"SGVsbG8=\"); // Uint8Array([72, 101, 108, 108, 111])\n * ```\n */\nexport function fromBase64(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\n/**\n * Compare two Uint8Arrays for equality using constant-time comparison.\n *\n * This function is designed to be resistant to timing attacks by always\n * comparing all bytes regardless of where a difference is found. The\n * comparison time depends only on the length of the arrays, not on where\n * they differ.\n *\n * **Security Note**: If the arrays have different lengths, this function\n * returns `false` immediately, which does leak length information. For\n * cryptographic uses where length should also be secret, ensure both\n * arrays are the same length before comparison.\n *\n * @param a - First byte array\n * @param b - Second byte array\n * @returns `true` if both arrays have the same length and identical contents\n *\n * @example\n * ```typescript\n * const key1 = new Uint8Array([1, 2, 3, 4]);\n * const key2 = new Uint8Array([1, 2, 3, 4]);\n * const key3 = new Uint8Array([1, 2, 3, 5]);\n *\n * bytesEqual(key1, key2); // true\n * bytesEqual(key1, key3); // false\n * ```\n */\nexport function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a[i] ^ b[i];\n }\n return result === 0;\n}\n","/**\n * SHA-256 cryptographic digest (32 bytes)\n *\n * Ported from bc-components-rust/src/digest.rs\n *\n * A `Digest` represents the cryptographic hash of some data. In this\n * implementation, SHA-256 is used, which produces a 32-byte hash value.\n * Digests are used throughout the crate for data verification and as unique\n * identifiers derived from data.\n *\n * # CBOR Serialization\n *\n * `Digest` implements the CBOR tagged encoding interfaces, which means it can be\n * serialized to and deserialized from CBOR with a specific tag (TAG_DIGEST = 40001).\n *\n * # UR Serialization\n *\n * When serialized as a Uniform Resource (UR), a `Digest` is represented as a\n * binary blob with the type \"digest\".\n *\n * @example\n * ```typescript\n * import { Digest } from '@bcts/components';\n *\n * // Create a digest from a string\n * const data = new TextEncoder().encode(\"hello world\");\n * const digest = Digest.fromImage(data);\n *\n * // Validate that the digest matches the original data\n * console.log(digest.validate(data)); // true\n *\n * // Create a digest from a hex string\n * const hexString = \"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9\";\n * const digest2 = Digest.fromHex(hexString);\n *\n * // Retrieve the digest as hex\n * console.log(digest2.hex()); // b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9\n * ```\n */\n\nimport { sha256, SHA256_SIZE } from \"@bcts/crypto\";\nimport {\n type Cbor,\n type Tag,\n type CborTaggedEncodable,\n type CborTaggedDecodable,\n toByteString,\n expectBytes,\n createTaggedCbor,\n validateTag,\n extractTaggedContent,\n decodeCbor,\n tagsForValues,\n} from \"@bcts/dcbor\";\nimport { DIGEST as TAG_DIGEST } from \"@bcts/tags\";\nimport { UR, type UREncodable } from \"@bcts/uniform-resources\";\nimport { CryptoError } from \"./error.js\";\nimport { bytesToHex, hexToBytes, toBase64 } from \"./utils.js\";\nimport type { DigestProvider } from \"./digest-provider.js\";\n\nexport class Digest\n implements DigestProvider, CborTaggedEncodable, CborTaggedDecodable<Digest>, UREncodable\n{\n static readonly DIGEST_SIZE = SHA256_SIZE;\n\n private readonly _data: Uint8Array;\n\n private constructor(data: Uint8Array) {\n if (data.length !== Digest.DIGEST_SIZE) {\n throw CryptoError.invalidSize(Digest.DIGEST_SIZE, data.length);\n }\n this._data = new Uint8Array(data);\n }\n\n /**\n * Get the digest data.\n */\n data(): Uint8Array {\n return this._data;\n }\n\n // ============================================================================\n // Static Factory Methods\n // ============================================================================\n\n /**\n * Create a Digest from a 32-byte array.\n */\n static fromData(data: Uint8Array): Digest {\n return new Digest(new Uint8Array(data));\n }\n\n /**\n * Create a Digest from data, validating the length.\n * Alias for fromData for compatibility with Rust API.\n */\n static fromDataRef(data: Uint8Array): Digest {\n return Digest.fromData(data);\n }\n\n /**\n * Create a Digest from hex string.\n *\n * @throws Error if the hex string is not exactly 64 characters.\n */\n static fromHex(hex: string): Digest {\n return new Digest(hexToBytes(hex));\n }\n\n /**\n * Compute SHA-256 digest of data (called \"image\" in Rust).\n *\n * @param image - The data to hash\n */\n static fromImage(image: Uint8Array): Digest {\n const hashData = sha256(image);\n return new Digest(new Uint8Array(hashData));\n }\n\n /**\n * Compute SHA-256 digest from multiple data parts.\n *\n * The parts are concatenated and then hashed.\n *\n * @param imageParts - Array of byte arrays to concatenate and hash\n */\n static fromImageParts(imageParts: Uint8Array[]): Digest {\n const totalLength = imageParts.reduce((sum, part) => sum + part.length, 0);\n const buf = new Uint8Array(totalLength);\n let offset = 0;\n for (const part of imageParts) {\n buf.set(part, offset);\n offset += part.length;\n }\n return Digest.fromImage(buf);\n }\n\n /**\n * Compute SHA-256 digest from an array of Digests.\n *\n * The digest bytes are concatenated and then hashed.\n *\n * @param digests - Array of Digests to combine\n */\n static fromDigests(digests: Digest[]): Digest {\n const buf = new Uint8Array(digests.length * Digest.DIGEST_SIZE);\n let offset = 0;\n for (const digest of digests) {\n buf.set(digest._data, offset);\n offset += Digest.DIGEST_SIZE;\n }\n return Digest.fromImage(buf);\n }\n\n /**\n * Compute SHA-256 digest of data (legacy alias for fromImage).\n * @deprecated Use fromImage instead\n */\n static hash(data: Uint8Array): Digest {\n return Digest.fromImage(data);\n }\n\n // ============================================================================\n // Instance Methods\n // ============================================================================\n\n /**\n * Get the raw digest bytes as a copy.\n */\n toData(): Uint8Array {\n return new Uint8Array(this._data);\n }\n\n /**\n * Get a reference to the raw digest bytes.\n */\n asBytes(): Uint8Array {\n return this._data;\n }\n\n /**\n * Get hex string representation.\n */\n hex(): string {\n return bytesToHex(this._data);\n }\n\n /**\n * Get hex string representation (alias for hex()).\n */\n toHex(): string {\n return this.hex();\n }\n\n /**\n * Get base64 representation.\n */\n toBase64(): string {\n return toBase64(this._data);\n }\n\n /**\n * Get the first four bytes of the digest as a hexadecimal string.\n * Useful for short descriptions.\n */\n shortDescription(): string {\n return bytesToHex(this._data.slice(0, 4));\n }\n\n /**\n * Validate the digest against the given image.\n *\n * The image is hashed with SHA-256 and compared to this digest.\n * @returns `true` if the digest matches the image.\n */\n validate(image: Uint8Array): boolean {\n return this.equals(Digest.fromImage(image));\n }\n\n /**\n * Compare with another Digest.\n */\n equals(other: Digest): boolean {\n if (this._data.length !== other._data.length) return false;\n for (let i = 0; i < this._data.length; i++) {\n if (this._data[i] !== other._data[i]) return false;\n }\n return true;\n }\n\n /**\n * Compare digests lexicographically.\n */\n compare(other: Digest): number {\n for (let i = 0; i < this._data.length; i++) {\n const a = this._data[i];\n const b = other._data[i];\n if (a < b) return -1;\n if (a > b) return 1;\n }\n return 0;\n }\n\n /**\n * Get string representation.\n */\n toString(): string {\n return `Digest(${this.hex()})`;\n }\n\n // ============================================================================\n // DigestProvider Implementation\n // ============================================================================\n\n /**\n * A Digest is its own digest provider - returns itself.\n */\n digest(): Digest {\n return this;\n }\n\n // ============================================================================\n // CBOR Serialization (CborTaggedEncodable)\n // ============================================================================\n\n /**\n * Returns the CBOR tags associated with Digest.\n */\n cborTags(): Tag[] {\n return tagsForValues([TAG_DIGEST.value]);\n }\n\n /**\n * Returns the untagged CBOR encoding (as a byte string).\n */\n untaggedCbor(): Cbor {\n return toByteString(this._data);\n }\n\n /**\n * Returns the tagged CBOR encoding.\n */\n taggedCbor(): Cbor {\n return createTaggedCbor(this);\n }\n\n /**\n * Returns the tagged value in CBOR binary representation.\n */\n taggedCborData(): Uint8Array {\n return this.taggedCbor().toData();\n }\n\n // ============================================================================\n // CBOR Deserialization (CborTaggedDecodable)\n // ============================================================================\n\n /**\n * Creates a Digest by decoding it from untagged CBOR.\n */\n fromUntaggedCbor(cbor: Cbor): Digest {\n const data = expectBytes(cbor);\n return Digest.fromData(data);\n }\n\n /**\n * Creates a Digest by decoding it from tagged CBOR.\n */\n fromTaggedCbor(cbor: Cbor): Digest {\n validateTag(cbor, this.cborTags());\n const content = extractTaggedContent(cbor);\n return this.fromUntaggedCbor(content);\n }\n\n /**\n * Static method to decode from tagged CBOR.\n */\n static fromTaggedCbor(cbor: Cbor): Digest {\n const instance = new Digest(new Uint8Array(Digest.DIGEST_SIZE));\n return instance.fromTaggedCbor(cbor);\n }\n\n /**\n * Static method to decode from tagged CBOR binary data.\n */\n static fromTaggedCborData(data: Uint8Array): Digest {\n const cbor = decodeCbor(data);\n return Digest.fromTaggedCbor(cbor);\n }\n\n /**\n * Static method to decode from untagged CBOR binary data.\n */\n static fromUntaggedCborData(data: Uint8Array): Digest {\n const cbor = decodeCbor(data);\n const bytes = expectBytes(cbor);\n return Digest.fromData(bytes);\n }\n\n // ============================================================================\n // UR Serialization (UREncodable)\n // ============================================================================\n\n /**\n * Returns the UR representation of the Digest.\n * Note: URs use untagged CBOR since the type is conveyed by the UR type itself.\n */\n ur(): UR {\n return UR.new(\"digest\", this.untaggedCbor());\n }\n\n /**\n * Returns the UR string representation.\n */\n urString(): string {\n return this.ur().string();\n }\n\n /**\n * Creates a Digest from a UR.\n */\n static fromUR(ur: UR): Digest {\n ur.checkType(\"digest\");\n const instance = new Digest(new Uint8Array(Digest.DIGEST_SIZE));\n return instance.fromUntaggedCbor(ur.cbor());\n }\n\n /**\n * Creates a Digest from a UR string.\n */\n static fromURString(urString: string): Digest {\n const ur = UR.fromURString(urString);\n return Digest.fromUR(ur);\n }\n\n // ============================================================================\n // Static Utility Methods\n // ============================================================================\n\n /**\n * Validate the given data against the digest, if any.\n *\n * Returns `true` if the digest is `undefined` or if the digest matches the\n * image's digest. Returns `false` if the digest does not match.\n */\n static validateOpt(image: Uint8Array, digest: Digest | undefined): boolean {\n if (digest === undefined) {\n return true;\n }\n return digest.validate(image);\n }\n}\n"],"mappings":";;;;;;;;;;;;AASA,IAAaA,gBAAb,MAAaA,sBAAoBC,YAAgB;CAC/C,OAAO,YAAY,UAAkB,QAA6B;AAChE,SAAO,IAAID,cAAY,0BAA0B,SAAS,QAAQ,SAAS;;CAG7E,OAAO,cAAc,SAA8B;AACjD,SAAO,IAAIA,cAAY,mBAAmB,UAAU;;CAGtD,OAAO,gBAAgB,SAA8B;AACnD,SAAO,IAAIA,cAAY,4BAA4B,UAAU;;CAG/D,OAAO,aAAa,SAA8B;AAChD,SAAO,IAAIA,cAAY,kBAAkB,UAAU;;CAGrD,OAAO,aAAa,MAAc,SAAiB,QAA6B;AAC9E,SAAO,IAAIA,cAAY,GAAG,KAAK,sBAAsB,QAAQ,QAAQ,SAAS;;CAGhF,OAAO,YAAY,SAA8B;AAC/C,SAAO,IAAIA,cAAY,iBAAiB,UAAU;;;AAMtD,SAAgB,QAAQ,QAAkC;AACxD,QAAO,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;ACjB3B,SAAgB,WAAW,MAA0B;AACnD,QAAO,MAAM,KAAK,KAAK,CACpB,KAAK,MAAM,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAC3C,KAAK,GAAG;;;;;;;;;;;;;;;;AAiBb,SAAgB,WAAW,KAAyB;AAClD,KAAI,IAAI,SAAS,MAAM,EACrB,OAAM,IAAI,MAAM,yCAAyC,IAAI,SAAS;AAExE,KAAI,CAAC,iBAAiB,KAAK,IAAI,CAC7B,OAAM,IAAI,MAAM,0DAA0D;CAE5E,MAAM,OAAO,IAAI,WAAW,IAAI,SAAS,EAAE;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,EACnC,MAAK,IAAI,KAAK,SAAS,IAAI,UAAU,GAAG,IAAI,EAAE,EAAE,GAAG;AAErD,QAAO;;;;;;;;;;;;;;;;;AAkBT,SAAgB,SAAS,MAA0B;CAGjD,IAAI,SAAS;AACb,MAAK,MAAM,QAAQ,KACjB,WAAU,OAAO,aAAa,KAAK;AAErC,QAAO,KAAK,OAAO;;;;;;;;;;;;;;;;AAiBrB,SAAgB,WAAW,QAA4B;CACrD,MAAM,SAAS,KAAK,OAAO;CAC3B,MAAM,QAAQ,IAAI,WAAW,OAAO,OAAO;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,IACjC,OAAM,KAAK,OAAO,WAAW,EAAE;AAEjC,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BT,SAAgB,WAAW,GAAe,GAAwB;AAChE,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;CAClC,IAAI,SAAS;AACb,MAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,IAC5B,WAAU,EAAE,KAAK,EAAE;AAErB,QAAO,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5EpB,IAAa,SAAb,MAAa,OAEb;CACE,OAAgB,cAAc;CAE9B,AAAiB;CAEjB,AAAQ,YAAY,MAAkB;AACpC,MAAI,KAAK,WAAW,OAAO,YACzB,OAAME,cAAY,YAAY,OAAO,aAAa,KAAK,OAAO;AAEhE,OAAK,QAAQ,IAAI,WAAW,KAAK;;;;;CAMnC,OAAmB;AACjB,SAAO,KAAK;;;;;CAUd,OAAO,SAAS,MAA0B;AACxC,SAAO,IAAI,OAAO,IAAI,WAAW,KAAK,CAAC;;;;;;CAOzC,OAAO,YAAY,MAA0B;AAC3C,SAAO,OAAO,SAAS,KAAK;;;;;;;CAQ9B,OAAO,QAAQ,KAAqB;AAClC,SAAO,IAAI,OAAO,WAAW,IAAI,CAAC;;;;;;;CAQpC,OAAO,UAAU,OAA2B;EAC1C,MAAM,WAAW,OAAO,MAAM;AAC9B,SAAO,IAAI,OAAO,IAAI,WAAW,SAAS,CAAC;;;;;;;;;CAU7C,OAAO,eAAe,YAAkC;EACtD,MAAM,cAAc,WAAW,QAAQ,KAAK,SAAS,MAAM,KAAK,QAAQ,EAAE;EAC1E,MAAM,MAAM,IAAI,WAAW,YAAY;EACvC,IAAI,SAAS;AACb,OAAK,MAAM,QAAQ,YAAY;AAC7B,OAAI,IAAI,MAAM,OAAO;AACrB,aAAU,KAAK;;AAEjB,SAAO,OAAO,UAAU,IAAI;;;;;;;;;CAU9B,OAAO,YAAY,SAA2B;EAC5C,MAAM,MAAM,IAAI,WAAW,QAAQ,SAAS,OAAO,YAAY;EAC/D,IAAI,SAAS;AACb,OAAK,MAAM,UAAU,SAAS;AAC5B,OAAI,IAAI,OAAO,OAAO,OAAO;AAC7B,aAAU,OAAO;;AAEnB,SAAO,OAAO,UAAU,IAAI;;;;;;CAO9B,OAAO,KAAK,MAA0B;AACpC,SAAO,OAAO,UAAU,KAAK;;;;;CAU/B,SAAqB;AACnB,SAAO,IAAI,WAAW,KAAK,MAAM;;;;;CAMnC,UAAsB;AACpB,SAAO,KAAK;;;;;CAMd,MAAc;AACZ,SAAO,WAAW,KAAK,MAAM;;;;;CAM/B,QAAgB;AACd,SAAO,KAAK,KAAK;;;;;CAMnB,WAAmB;AACjB,SAAO,SAAS,KAAK,MAAM;;;;;;CAO7B,mBAA2B;AACzB,SAAO,WAAW,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC;;;;;;;;CAS3C,SAAS,OAA4B;AACnC,SAAO,KAAK,OAAO,OAAO,UAAU,MAAM,CAAC;;;;;CAM7C,OAAO,OAAwB;AAC7B,MAAI,KAAK,MAAM,WAAW,MAAM,MAAM,OAAQ,QAAO;AACrD,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,IACrC,KAAI,KAAK,MAAM,OAAO,MAAM,MAAM,GAAI,QAAO;AAE/C,SAAO;;;;;CAMT,QAAQ,OAAuB;AAC7B,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;GAC1C,MAAM,IAAI,KAAK,MAAM;GACrB,MAAM,IAAI,MAAM,MAAM;AACtB,OAAI,IAAI,EAAG,QAAO;AAClB,OAAI,IAAI,EAAG,QAAO;;AAEpB,SAAO;;;;;CAMT,WAAmB;AACjB,SAAO,UAAU,KAAK,KAAK,CAAC;;;;;CAU9B,SAAiB;AACf,SAAO;;;;;CAUT,WAAkB;AAChB,SAAO,cAAc,CAACC,OAAW,MAAM,CAAC;;;;;CAM1C,eAAqB;AACnB,SAAO,aAAa,KAAK,MAAM;;;;;CAMjC,aAAmB;AACjB,SAAO,iBAAiB,KAAK;;;;;CAM/B,iBAA6B;AAC3B,SAAO,KAAK,YAAY,CAAC,QAAQ;;;;;CAUnC,iBAAiB,QAAoB;EACnC,MAAM,OAAO,YAAYC,OAAK;AAC9B,SAAO,OAAO,SAAS,KAAK;;;;;CAM9B,eAAe,QAAoB;AACjC,cAAYA,QAAM,KAAK,UAAU,CAAC;EAClC,MAAM,UAAU,qBAAqBA,OAAK;AAC1C,SAAO,KAAK,iBAAiB,QAAQ;;;;;CAMvC,OAAO,eAAe,QAAoB;AAExC,SADiB,IAAI,OAAO,IAAI,WAAW,OAAO,YAAY,CAAC,CAC/C,eAAeA,OAAK;;;;;CAMtC,OAAO,mBAAmB,MAA0B;EAClD,MAAMA,SAAO,WAAW,KAAK;AAC7B,SAAO,OAAO,eAAeA,OAAK;;;;;CAMpC,OAAO,qBAAqB,MAA0B;EAEpD,MAAM,QAAQ,YADD,WAAW,KAAK,CACE;AAC/B,SAAO,OAAO,SAAS,MAAM;;;;;;CAW/B,KAAS;AACP,SAAO,GAAG,IAAI,UAAU,KAAK,cAAc,CAAC;;;;;CAM9C,WAAmB;AACjB,SAAO,KAAK,IAAI,CAAC,QAAQ;;;;;CAM3B,OAAO,OAAO,IAAgB;AAC5B,KAAG,UAAU,SAAS;AAEtB,SADiB,IAAI,OAAO,IAAI,WAAW,OAAO,YAAY,CAAC,CAC/C,iBAAiB,GAAG,MAAM,CAAC;;;;;CAM7C,OAAO,aAAa,UAA0B;EAC5C,MAAM,KAAK,GAAG,aAAa,SAAS;AACpC,SAAO,OAAO,OAAO,GAAG;;;;;;;;CAa1B,OAAO,YAAY,OAAmB,QAAqC;AACzE,MAAI,WAAW,OACb,QAAO;AAET,SAAO,OAAO,SAAS,MAAM"}
|