@zkim-platform/file-format 1.0.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.
package/README.md ADDED
@@ -0,0 +1,695 @@
1
+ # @zkim/file-format
2
+
3
+ ![npm version](https://img.shields.io/npm/v/@zkim/file-format)
4
+ ![npm downloads](https://img.shields.io/npm/dm/@zkim/file-format)
5
+ ![License](https://img.shields.io/npm/l/@zkim/file-format)
6
+ ![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue)
7
+ ![Node.js](https://img.shields.io/badge/Node.js-18%2B-green)
8
+ ![Test Coverage](https://img.shields.io/badge/coverage-92%25-brightgreen)
9
+ ![Build Status](https://github.com/zkdotim/zkim-file-format/workflows/CI/badge.svg)
10
+
11
+ Secure, encrypted file format with three-layer encryption, integrity validation, and privacy-preserving search capabilities.
12
+
13
+ ## 📊 Project Status
14
+
15
+ - **Version:** 1.0.0
16
+ - **Tests:** 1,307 passing (99.8% pass rate)
17
+ - **Coverage:** 92.09% statements, 82.15% branches, 95.83% functions
18
+ - **Build:** ✅ Passing
19
+ - **License:** MIT
20
+ - **Status:** Production Ready
21
+
22
+ ## Features
23
+
24
+ - 🔐 **Three-Layer Encryption**: XChaCha20-Poly1305 encryption with platform, user, and content layers
25
+ - 🔍 **Privacy-Preserving Search**: Searchable encryption with OPRF-based trapdoors and rotation
26
+ - ✅ **Integrity Validation**: BLAKE3-based integrity checks and Ed25519 signatures
27
+ - 📦 **Compression Support**: Optional GZIP/Brotli compression for efficient storage
28
+ - 🛡️ **Error Recovery**: Advanced error detection and recovery mechanisms
29
+ - ⚡ **Performance Monitoring**: Built-in performance tracking and optimization
30
+ - 🔒 **Constant-Time Security**: Timing attack prevention for cryptographic operations
31
+ - 🌐 **Cross-Platform**: Works in both browser and Node.js environments
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ npm install @zkim/file-format
37
+ ```
38
+
39
+ ### Requirements
40
+
41
+ - Node.js 18+ (for Node.js environments)
42
+ - Modern browser with TypedArray and ES2020+ support (for browser environments)
43
+ - TypeScript 5.0+ (recommended for type safety)
44
+
45
+ ### Dependencies
46
+
47
+ This package includes the following dependencies (automatically installed):
48
+
49
+ - `@noble/curves` - Ristretto255 operations for searchable encryption
50
+ - `@noble/hashes` - BLAKE3 hashing (standard ZKIM hash algorithm)
51
+ - `libsodium-wrappers-sumo` - Cryptographic operations (encryption, decryption, key generation)
52
+
53
+ These are bundled with the package and do not need to be installed separately.
54
+
55
+ ## Quick Start
56
+
57
+ ### Basic Usage
58
+
59
+ ```typescript
60
+ import { ZKIMFileService, InMemoryStorage, defaultLogger } from "@zkim/file-format";
61
+ import sodium from "libsodium-wrappers-sumo";
62
+
63
+ async function main() {
64
+ // Wait for libsodium to be ready
65
+ await sodium.ready;
66
+
67
+ // Generate encryption keys
68
+ const platformKey = sodium.randombytes_buf(32);
69
+ const userKey = sodium.randombytes_buf(32);
70
+ const userId = "example-user";
71
+
72
+ // Create storage backend (optional - in-memory for this example)
73
+ const storage = new InMemoryStorage();
74
+
75
+ // Initialize the file service
76
+ const fileService = new ZKIMFileService(
77
+ {
78
+ enableCompression: true,
79
+ enableSearchableEncryption: false,
80
+ enableIntegrityValidation: true,
81
+ },
82
+ defaultLogger,
83
+ storage
84
+ );
85
+
86
+ await fileService.initialize();
87
+
88
+ // Create some test data
89
+ const testData = new TextEncoder().encode("Hello, ZKIM File Format!");
90
+
91
+ // Create an encrypted ZKIM file
92
+ const result = await fileService.createZkimFile(
93
+ testData,
94
+ userId,
95
+ platformKey,
96
+ userKey,
97
+ {
98
+ fileName: "example.txt",
99
+ mimeType: "text/plain",
100
+ }
101
+ );
102
+
103
+ if (!result.success || !result.file) {
104
+ throw new Error("Failed to create file");
105
+ }
106
+
107
+ // File created successfully
108
+ const fileId = result.file.header.fileId;
109
+
110
+ // Retrieve the file
111
+ const retrievedResult = await fileService.getZkimFile(
112
+ result.objectId ?? result.file.header.fileId
113
+ );
114
+
115
+ if (!retrievedResult.success || !retrievedResult.data) {
116
+ throw new Error(`Failed to retrieve file: ${retrievedResult.error}`);
117
+ }
118
+
119
+ // Decrypt the file
120
+ const decryptedData = await fileService.decryptZkimFile(
121
+ retrievedResult.data,
122
+ userId,
123
+ userKey
124
+ );
125
+
126
+ const decryptedText = new TextDecoder().decode(decryptedData);
127
+ // File decrypted successfully
128
+
129
+ // Cleanup
130
+ await fileService.cleanup();
131
+ }
132
+
133
+ main().catch((error) => {
134
+ // Handle error appropriately
135
+ throw error;
136
+ });
137
+ ```
138
+
139
+ ## API Reference
140
+
141
+ ### Core Services
142
+
143
+ #### `ZKIMFileService`
144
+
145
+ Main service for creating, managing, and operating on ZKIM files.
146
+
147
+ ```typescript
148
+ import { ZKIMFileService } from "@zkim/file-format";
149
+
150
+ const fileService = new ZKIMFileService(config?, logger?, storage?);
151
+ await fileService.initialize();
152
+
153
+ // Create a file
154
+ const result = await fileService.createZkimFile(
155
+ content: Uint8Array,
156
+ userId: string,
157
+ platformKey: Uint8Array,
158
+ userKey: Uint8Array,
159
+ metadata?: ZkimFileMetadata
160
+ );
161
+
162
+ // Retrieve a file
163
+ const file = await fileService.getZkimFile(objectId: string);
164
+
165
+ // Decrypt a file
166
+ const decrypted = await fileService.decryptZkimFile(
167
+ file: ZkimFile,
168
+ userId: string,
169
+ userKey: Uint8Array
170
+ );
171
+ ```
172
+
173
+ #### `ZkimEncryption`
174
+
175
+ Three-layer encryption service for encrypting and decrypting data.
176
+
177
+ ```typescript
178
+ import { ZkimEncryption } from "@zkim/file-format";
179
+
180
+ const encryption = new ZkimEncryption(config?, logger?);
181
+ await encryption.initialize();
182
+
183
+ // Encrypt data
184
+ const encrypted = await encryption.encryptData(
185
+ data: Uint8Array,
186
+ platformKey: Uint8Array,
187
+ userKey: Uint8Array,
188
+ fileId: string,
189
+ metadata?: Record<string, unknown>
190
+ );
191
+
192
+ // Decrypt data
193
+ const decrypted = await encryption.decrypt(
194
+ encryptedData: Uint8Array,
195
+ key: Uint8Array,
196
+ nonce: Uint8Array
197
+ );
198
+ ```
199
+
200
+ #### `ZkimIntegrity`
201
+
202
+ Integrity validation service for validating file integrity and detecting tampering.
203
+
204
+ ```typescript
205
+ import { ZkimIntegrity } from "@zkim/file-format";
206
+
207
+ const integrity = new ZkimIntegrity(config?, logger?);
208
+ await integrity.initialize();
209
+
210
+ // Validate file
211
+ const result = await integrity.validateFile(
212
+ file: ZkimFile,
213
+ platformKey?: Uint8Array,
214
+ userKey?: Uint8Array
215
+ );
216
+
217
+ // Detect tampering
218
+ const tampering = await integrity.detectTampering(file: ZkimFile);
219
+ ```
220
+
221
+ #### `SearchableEncryption`
222
+
223
+ Privacy-preserving search service using OPRF-based trapdoors.
224
+
225
+ ```typescript
226
+ import { SearchableEncryption } from "@zkim/file-format";
227
+
228
+ const search = new SearchableEncryption(config?, logger?);
229
+ await search.initialize();
230
+
231
+ // Index a file
232
+ await search.indexFile(file: ZkimFile, keywords: string[]);
233
+
234
+ // Search for files
235
+ const results = await search.search(
236
+ query: string,
237
+ limit?: number
238
+ );
239
+ ```
240
+
241
+ ### Configuration Options
242
+
243
+ #### `ZKIMFileServiceConfig`
244
+
245
+ ```typescript
246
+ interface ZKIMFileServiceConfig {
247
+ enableCompression?: boolean; // Enable compression (default: true)
248
+ enableDeduplication?: boolean; // Enable deduplication (default: true)
249
+ chunkSize?: number; // Chunk size in bytes (default: 512KB)
250
+ compressionLevel?: number; // Compression level 1-9 (default: 6)
251
+ compressionAlgorithm?: "brotli" | "gzip"; // Compression algorithm (default: "gzip")
252
+ enableSearchableEncryption?: boolean; // Enable searchable encryption (default: true)
253
+ enableIntegrityValidation?: boolean; // Enable integrity validation (default: true)
254
+ enableMetadataIndexing?: boolean; // Enable metadata indexing (default: true)
255
+ maxFileSize?: number; // Maximum file size in bytes (default: 10GB)
256
+ enableStreaming?: boolean; // Enable streaming (default: true)
257
+ }
258
+ ```
259
+
260
+ #### `ZkimEncryptionConfig`
261
+
262
+ ```typescript
263
+ interface ZkimEncryptionConfig {
264
+ enableThreeLayerEncryption?: boolean; // Enable three-layer encryption (default: true)
265
+ enableKeyRotation?: boolean; // Enable key rotation (default: true)
266
+ enablePerfectForwardSecrecy?: boolean; // Enable PFS (default: true)
267
+ enableCompromiseDetection?: boolean; // Enable compromise detection (default: true)
268
+ defaultAlgorithm?: string; // Default encryption algorithm (default: "xchacha20-poly1305")
269
+ keySize?: number; // Key size in bytes (default: 32)
270
+ nonceSize?: number; // Nonce size in bytes (default: 24)
271
+ compressionEnabled?: boolean; // Enable compression (default: true)
272
+ compressionAlgorithm?: "gzip" | "brotli"; // Compression algorithm (default: "gzip")
273
+ compressionLevel?: number; // Compression level 1-9 (default: 6)
274
+ }
275
+ ```
276
+
277
+ #### `ZkimIntegrityConfig`
278
+
279
+ ```typescript
280
+ interface ZkimIntegrityConfig {
281
+ enableHeaderValidation?: boolean; // Enable header validation (default: true)
282
+ enableChunkValidation?: boolean; // Enable chunk validation (default: true)
283
+ enableSignatureValidation?: boolean; // Enable signature validation (default: true)
284
+ enableMetadataValidation?: boolean; // Enable metadata validation (default: true)
285
+ enableTamperDetection?: boolean; // Enable tamper detection (default: true)
286
+ validationThreshold?: number; // Validation threshold 0-1 (default: 0.95)
287
+ enableAuditLogging?: boolean; // Enable audit logging (default: true)
288
+ enablePerformanceMetrics?: boolean; // Enable performance metrics (default: true)
289
+ hashAlgorithm?: string; // Hash algorithm (default: "blake3")
290
+ signatureAlgorithm?: string; // Signature algorithm (default: "ed25519")
291
+ }
292
+ ```
293
+
294
+ ### Storage Backends
295
+
296
+ #### `InMemoryStorage`
297
+
298
+ In-memory storage backend for testing and temporary storage.
299
+
300
+ ```typescript
301
+ import { InMemoryStorage } from "@zkim/file-format";
302
+
303
+ const storage = new InMemoryStorage();
304
+ const fileService = new ZKIMFileService(config, logger, storage);
305
+ ```
306
+
307
+ #### `LocalStorageBackend`
308
+
309
+ Browser localStorage-based storage backend.
310
+
311
+ ```typescript
312
+ import { LocalStorageBackend } from "@zkim/file-format";
313
+
314
+ const storage = new LocalStorageBackend();
315
+ const fileService = new ZKIMFileService(config, logger, storage);
316
+ ```
317
+
318
+ #### Custom Storage Backend
319
+
320
+ Implement the `IStorageBackend` interface for custom storage:
321
+
322
+ ```typescript
323
+ import { IStorageBackend } from "@zkim/file-format";
324
+
325
+ class CustomStorage implements IStorageBackend {
326
+ async get(key: string): Promise<Uint8Array | null> {
327
+ // Implement retrieval logic
328
+ }
329
+
330
+ async set(key: string, value: Uint8Array): Promise<void> {
331
+ // Implement storage logic
332
+ }
333
+
334
+ async delete(key: string): Promise<void> {
335
+ // Implement deletion logic
336
+ }
337
+
338
+ async list(): Promise<string[]> {
339
+ // Implement listing logic
340
+ }
341
+ }
342
+ ```
343
+
344
+ ### Utilities
345
+
346
+ #### Crypto Utilities
347
+
348
+ ```typescript
349
+ import {
350
+ generateRandomBytes,
351
+ generateRandomHex,
352
+ hashData,
353
+ hashDataToHex,
354
+ generateKeyPair,
355
+ generateSigningKeyPair,
356
+ encryptData,
357
+ decryptData,
358
+ toBase64,
359
+ fromBase64,
360
+ toHex,
361
+ fromHex,
362
+ } from "@zkim/file-format";
363
+
364
+ // Generate random bytes
365
+ const randomBytes = await generateRandomBytes(32);
366
+
367
+ // Hash data
368
+ const hash = hashData(data, 32); // 32-byte hash
369
+ const hashHex = hashDataToHex(data, 32);
370
+
371
+ // Generate key pairs
372
+ const keyPair = await generateKeyPair(); // X25519
373
+ const signingKeyPair = await generateSigningKeyPair(); // Ed25519
374
+
375
+ // Encrypt/decrypt
376
+ const encrypted = await encryptData(data, key, nonce);
377
+ const decrypted = await decryptData(encrypted.ciphertext, key, encrypted.nonce);
378
+
379
+ // Base64 encoding
380
+ const base64 = await toBase64(data);
381
+ const decoded = await fromBase64(base64);
382
+ ```
383
+
384
+ #### Compression Utilities
385
+
386
+ ```typescript
387
+ import { compressGzip, decompressGzip } from "@zkim/file-format";
388
+
389
+ // Compress data
390
+ const compressed = await compressGzip(data);
391
+
392
+ // Decompress data
393
+ const decompressed = await decompressGzip(compressed);
394
+ ```
395
+
396
+ ## Examples
397
+
398
+ ### Example 1: Basic File Encryption
399
+
400
+ ```typescript
401
+ import { ZKIMFileService, InMemoryStorage } from "@zkim/file-format";
402
+ import sodium from "libsodium-wrappers-sumo";
403
+
404
+ await sodium.ready;
405
+
406
+ const platformKey = sodium.randombytes_buf(32);
407
+ const userKey = sodium.randombytes_buf(32);
408
+ const storage = new InMemoryStorage();
409
+
410
+ const fileService = new ZKIMFileService(
411
+ { enableCompression: true },
412
+ undefined,
413
+ storage
414
+ );
415
+ await fileService.initialize();
416
+
417
+ const content = new TextEncoder().encode("Secret message");
418
+ const result = await fileService.createZkimFile(
419
+ content,
420
+ "user-123",
421
+ platformKey,
422
+ userKey,
423
+ { fileName: "secret.txt", mimeType: "text/plain" }
424
+ );
425
+
426
+ if (result.success && result.file) {
427
+ // File created successfully
428
+ const fileId = result.file.header.fileId;
429
+ }
430
+ ```
431
+
432
+ ### Example 2: Integrity Validation
433
+
434
+ ```typescript
435
+ import { ZkimIntegrity } from "@zkim/file-format";
436
+
437
+ const integrity = new ZkimIntegrity();
438
+ await integrity.initialize();
439
+
440
+ const validationResult = await integrity.validateFile(
441
+ zkimFile,
442
+ platformKey,
443
+ userKey
444
+ );
445
+
446
+ if (validationResult.isValid) {
447
+ // File is valid
448
+ } else {
449
+ // Handle validation errors
450
+ const errors = validationResult.errors;
451
+ }
452
+ ```
453
+
454
+ ### Example 3: Searchable Encryption
455
+
456
+ ```typescript
457
+ import { SearchableEncryption } from "@zkim/file-format";
458
+
459
+ const search = new SearchableEncryption();
460
+ await search.initialize();
461
+
462
+ // Index a file with keywords
463
+ await search.indexFile(zkimFile, ["document", "important", "2025"]);
464
+
465
+ // Search for files
466
+ const results = await search.search("document", 10);
467
+ // Found results.length files
468
+ ```
469
+
470
+ ## Security Considerations
471
+
472
+ ### Web Crypto API Prohibition
473
+
474
+ **CRITICAL**: This package **PROHIBITS** the use of Web Crypto API (`crypto.subtle`, `crypto.getRandomValues`, `window.crypto`) for security and consistency reasons.
475
+
476
+ **Required patterns:**
477
+ - ✅ Use `libsodium-wrappers-sumo` for all cryptographic operations
478
+ - ✅ Use `@noble/hashes` for BLAKE3 hashing
479
+ - ✅ Use `sodium.randombytes_buf()` for random number generation
480
+ - ✅ Always call `await sodium.ready` before using libsodium functions
481
+
482
+ **Forbidden patterns:**
483
+ - ❌ `crypto.subtle.*` - All Web Crypto API subtle methods
484
+ - ❌ `crypto.getRandomValues()` - Web Crypto API random generation
485
+ - ❌ `window.crypto.*` - Web Crypto API access
486
+ - ❌ `WebCrypto`, `CryptoKey`, `SubtleCrypto` - Web Crypto API types
487
+
488
+ This prohibition is enforced by ESLint and will cause build failures if violated.
489
+
490
+ ### Key Management
491
+
492
+ - **Never store keys in plaintext**: Always use secure key storage mechanisms
493
+ - **Use proper key derivation**: Use Argon2id for password-based key derivation
494
+ - **Rotate keys regularly**: Implement key rotation policies
495
+ - **Protect keys in memory**: Clear sensitive data from memory when possible
496
+
497
+ ### Best Practices
498
+
499
+ 1. **Always validate file integrity** before decryption
500
+ 2. **Use constant-time comparisons** for security-sensitive operations
501
+ 3. **Enable all security features** in production (integrity validation, signature verification)
502
+ 4. **Monitor for tampering** using `detectTampering()`
503
+ 5. **Use secure random number generation** for all cryptographic operations
504
+ 6. **Implement proper error handling** to avoid information leakage
505
+
506
+ ### Cryptographic Algorithms
507
+
508
+ - **Encryption**: XChaCha20-Poly1305 (AEAD) via libsodium
509
+ - **Hashing**: BLAKE3 (256-bit output) via @noble/hashes
510
+ - **Signatures**: Ed25519 via libsodium
511
+ - **Key Exchange**: X25519 via libsodium
512
+ - **Searchable Encryption**: OPRF (Oblivious Pseudorandom Function) via @noble/curves
513
+ - **Random Generation**: libsodium `randombytes_buf()`
514
+
515
+ ## Troubleshooting
516
+
517
+ ### Common Issues
518
+
519
+ #### "libsodium is not ready"
520
+
521
+ **Solution**: Always wait for `sodium.ready` before using cryptographic functions:
522
+
523
+ ```typescript
524
+ import sodium from "libsodium-wrappers-sumo";
525
+ await sodium.ready;
526
+ // Now you can use crypto functions
527
+ ```
528
+
529
+ #### "Storage backend not available"
530
+
531
+ **Solution**: Provide a storage backend or use `InMemoryStorage`:
532
+
533
+ ```typescript
534
+ const storage = new InMemoryStorage();
535
+ const fileService = new ZKIMFileService(config, logger, storage);
536
+ ```
537
+
538
+ #### "Decryption failed"
539
+
540
+ **Possible causes**:
541
+ - Wrong encryption key
542
+ - Corrupted file data
543
+ - Missing nonce or metadata
544
+
545
+ **Solution**: Validate file integrity first, then check keys:
546
+
547
+ ```typescript
548
+ const validation = await integrity.validateFile(file, platformKey, userKey);
549
+ if (!validation.isValid) {
550
+ // Handle validation errors
551
+ const errors = validation.errors;
552
+ }
553
+ ```
554
+
555
+ #### "Compression not working"
556
+
557
+ **Solution**:
558
+ - **Node.js**: `zlib` is built-in and used automatically
559
+ - **Browser**: The package includes fallback compression using `pako`-compatible algorithms. No additional installation needed.
560
+
561
+ If you encounter compression issues, ensure your environment supports TypedArray operations.
562
+
563
+ ## TypeScript Support
564
+
565
+ This package is written in TypeScript and includes full type definitions. All types are exported and can be imported:
566
+
567
+ ```typescript
568
+ import type {
569
+ ZkimFile,
570
+ ZkimFileHeader,
571
+ ZkimFileMetadata,
572
+ ZKIMFileServiceConfig,
573
+ ZkimEncryptionConfig,
574
+ SearchQuery,
575
+ SearchResult,
576
+ } from "@zkim/file-format";
577
+ ```
578
+
579
+ ## Browser Support
580
+
581
+ This package works in modern browsers with:
582
+ - TypedArray support
583
+ - ES2020+ features
584
+ - ES Modules support
585
+ - `libsodium-wrappers-sumo` for cryptographic operations
586
+ - `@noble/hashes` for BLAKE3 hashing
587
+
588
+ Tested in:
589
+ - Chrome 90+
590
+ - Firefox 88+
591
+ - Safari 14+
592
+ - Edge 90+
593
+
594
+ ## Node.js Support
595
+
596
+ This package works in Node.js 18+ with:
597
+ - Built-in `zlib` for compression (GZIP)
598
+ - `libsodium-wrappers-sumo` for cryptographic operations
599
+ - `@noble/hashes` for BLAKE3 hashing
600
+ - ES Modules (ESM) support
601
+
602
+ ## Contributing
603
+
604
+ Contributions are welcome! Please see our [Contributing Guide](../../CONTRIBUTING.md) for details.
605
+
606
+ ### Development Setup
607
+
608
+ ```bash
609
+ # Clone the repository
610
+ git clone https://github.com/zkdotim/zkim-file-format.git
611
+ cd zkim-file-format
612
+
613
+ # Install dependencies
614
+ npm install
615
+
616
+ # Run tests
617
+ npm test
618
+
619
+ # Build the package
620
+ npm run build
621
+
622
+ # Run linting
623
+ npm run lint
624
+
625
+ # Run type checking
626
+ npm run typecheck
627
+
628
+ # Generate test coverage
629
+ npm run test:coverage
630
+ ```
631
+
632
+ ### CI/CD
633
+
634
+ This package uses GitHub Actions for continuous integration:
635
+
636
+ - **Lint & Type Check**: Runs on every push and pull request
637
+ - **Tests**: Automated testing with coverage reporting
638
+ - **Build**: Verifies package builds successfully
639
+ - **Security**: Automated security scanning
640
+ - **Publishing**: Automated npm publishing on release tags
641
+
642
+ See `.github/workflows/` for workflow definitions.
643
+
644
+ ## 📊 Statistics
645
+
646
+ - **Total Tests:** 1,307 (1,305 passing, 2 skipped)
647
+ - **Test Coverage:** 92.09% statements, 82.15% branches, 95.83% functions, 92.16% lines
648
+ - **Dependencies:** 3 production dependencies (libsodium, @noble/hashes, @noble/curves)
649
+ - **Bundle Size:** ~384 KB (ESM), ~390 KB (CJS)
650
+ - **TypeScript:** Full type definitions included
651
+
652
+ ## 🤝 Contributing
653
+
654
+ Contributions are welcome! Please see our [Contributing Guide](./CONTRIBUTING.md) for details.
655
+
656
+ ### Quick Start for Contributors
657
+
658
+ ```bash
659
+ # Clone the repository
660
+ git clone https://github.com/zkdotim/zkim-file-format.git
661
+ cd zkim-file-format
662
+
663
+ # Install dependencies
664
+ npm install
665
+
666
+ # Run tests
667
+ npm test
668
+
669
+ # Run linting
670
+ npm run lint
671
+
672
+ # Build the package
673
+ npm run build
674
+ ```
675
+
676
+ ## 📚 Support & Resources
677
+
678
+ - 📖 [Full Documentation](./README.md)
679
+ - 🐛 [Report a Bug](https://github.com/zkdotim/zkim-file-format/issues/new?template=bug_report.md)
680
+ - 💡 [Request a Feature](https://github.com/zkdotim/zkim-file-format/issues/new?template=feature_request.md)
681
+ - ❓ [Ask a Question](https://github.com/zkdotim/zkim-file-format/issues/new?template=question.md)
682
+ - 💬 [Discussions](https://github.com/zkdotim/zkim-file-format/discussions)
683
+ - 🔒 [Security Policy](./.github/SECURITY.md)
684
+
685
+ ## 📄 Changelog
686
+
687
+ See [CHANGELOG.md](./CHANGELOG.md) for a list of changes and version history.
688
+
689
+ ## 📜 License
690
+
691
+ MIT License - see [LICENSE](./LICENSE) for details.
692
+
693
+ ---
694
+
695
+ **Made with ❤️ by the ZKIM Team**