@smartledger/envelope 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/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Gregory Ward (aka Codenlighten)
4
+ Founder: Codenlighten.org
5
+ Co-founder & Chief Technology Officer: SmartLedger.Technology
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,452 @@
1
+ # @smartledger/envelope
2
+
3
+ **Simple, verifiable content signing for any application.**
4
+
5
+ A lightweight signing primitive that wraps content with cryptographic proof. Use it to build verifiable AI responses, signed documents, authenticated API calls, or audit trails.
6
+
7
+ ---
8
+
9
+ ## Quick Start
10
+
11
+ ```typescript
12
+ import { createAppIdentity } from '@smartledger/envelope';
13
+
14
+ // Create an identity (in-memory keys)
15
+ const identity = await createAppIdentity({ name: 'MyCoolApp' });
16
+
17
+ // Sign anything
18
+ const signed = await identity.signJson({ message: "Hello, world!" });
19
+
20
+ // Verify anything
21
+ const result = await identity.verifyJson(signed);
22
+ console.log('Valid:', result.valid); // true
23
+ ```
24
+
25
+ **Keys are ephemeral (in-memory) by default.** For persistence, see [Storage Examples](#storage-examples) below.
26
+
27
+ ---
28
+
29
+ ## What It Does
30
+
31
+ This package provides:
32
+
33
+ 1. **SignedEnvelope format** - A standard schema for signed content
34
+ 2. **Simple API** - One-line setup, easy signing/verification
35
+ 3. **Post-quantum support** - ML-DSA-87 (NIST FIPS 204) by default
36
+ 4. **Flexible** - Works with any JSON-serializable data
37
+
38
+ ### What It Doesn't Do
39
+
40
+ This is a **primitive**, not a complete application. It doesn't include:
41
+
42
+ - ❌ Persistent key storage (but see [examples](#storage-examples) for how to add it)
43
+ - ❌ DID generation or resolution
44
+ - ❌ Verifiable Credentials
45
+ - ❌ Blockchain integration
46
+ - ❌ KYC or identity verification
47
+
48
+ Those features belong in your application or separate packages. This library gives you the cryptographic foundation to build them.
49
+
50
+ ---
51
+
52
+ ## Use Cases
53
+
54
+ ### Verifiable AI Responses
55
+
56
+ ```typescript
57
+ import OpenAI from 'openai';
58
+
59
+ const identity = await createAppIdentity({ name: 'MyAI' });
60
+ const openai = new OpenAI();
61
+
62
+ const response = await openai.chat.completions.create({
63
+ model: 'gpt-4',
64
+ messages: [{ role: 'user', content: 'Explain quantum computing' }]
65
+ });
66
+
67
+ // Sign the AI response
68
+ const signed = await identity.signJson(response, {
69
+ contentType: 'ai-response'
70
+ });
71
+
72
+ // Now you have cryptographic proof of what your AI said and when
73
+ ```
74
+
75
+ ### Signed Content / Blog Posts
76
+
77
+ ```typescript
78
+ const identity = await createAppIdentity({ name: 'MyBlog' });
79
+
80
+ const post = {
81
+ title: "Why Cryptography Matters",
82
+ content: "...",
83
+ author: "Alice",
84
+ };
85
+
86
+ const signedPost = await identity.signJson(post, {
87
+ contentType: 'blog-post'
88
+ });
89
+
90
+ // Readers can verify authenticity
91
+ // Authors can't deny writing it
92
+ // Editors can't change it without detection
93
+ ```
94
+
95
+ ### Microservice Authentication
96
+
97
+ ```typescript
98
+ // Service A signs requests
99
+ const serviceA = await createAppIdentity({ name: 'ServiceA' });
100
+ const request = await serviceA.signJson({
101
+ action: 'process-payment',
102
+ amount: 100,
103
+ });
104
+
105
+ // Service B verifies before processing
106
+ const result = await serviceB.verifyJson(request);
107
+ if (result.valid && result.creator === 'ServiceA') {
108
+ // Process - we know it's really from ServiceA
109
+ }
110
+ ```
111
+
112
+ ### Audit Trails with Chain of Custody
113
+
114
+ ```typescript
115
+ import { createEnvelopeChain } from '@smartledger/envelope';
116
+
117
+ const original = await identity.signJson(
118
+ { status: 'draft', content: '...' }
119
+ );
120
+
121
+ // Link revision to original
122
+ const revision = await createEnvelopeChain(
123
+ identity.getSDK(),
124
+ identity.keyId,
125
+ { status: 'reviewed', content: '...' },
126
+ original,
127
+ { creator: 'reviewer' }
128
+ );
129
+
130
+ // revision.meta.parentId === hash(original)
131
+ // Full provenance chain preserved
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Features
137
+
138
+ ### 🔐 Post-Quantum Ready
139
+
140
+ Uses ML-DSA-87 (NIST FIPS 204) by default - quantum-resistant signatures:
141
+
142
+ ```typescript
143
+ const identity = await createAppIdentity({
144
+ name: 'MyApp',
145
+ algorithm: 'ml-dsa-87' // Default
146
+ });
147
+ ```
148
+
149
+ Or use ECDSA for Bitcoin compatibility:
150
+
151
+ ```typescript
152
+ const identity = await createAppIdentity({
153
+ name: 'MyApp',
154
+ algorithm: 'bsv-ecdsa-secp256k1'
155
+ });
156
+ ```
157
+
158
+ ### 📜 Chain of Custody
159
+
160
+ Link envelopes to create verifiable revision chains:
161
+
162
+ ```typescript
163
+ const updated = await createEnvelopeChain(
164
+ sdk, keyId, updatedData, originalEnvelope,
165
+ { creator: 'editor' }
166
+ );
167
+ // updated.meta.parentId === hash(originalEnvelope)
168
+ ```
169
+
170
+ ### 🔗 Extensible Metadata
171
+
172
+ Add custom metadata for your use case:
173
+
174
+ ```typescript
175
+ const signed = await createSignedEnvelope(sdk, keyId, data, {
176
+ creator: 'MyApp',
177
+ contentType: 'invoice',
178
+ metadata: {
179
+ invoiceNumber: 'INV-001',
180
+ customField: 'anything'
181
+ }
182
+ });
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Envelope Format
188
+
189
+ The `SignedEnvelope` is a simple, universal format:
190
+
191
+ ```typescript
192
+ interface SignedEnvelope<T> {
193
+ payload: T; // Your actual data
194
+
195
+ meta: {
196
+ version: string; // Schema version
197
+ creator: string; // Who created it
198
+ createdAt: string; // ISO 8601 timestamp
199
+ contentType?: string; // Optional type hint
200
+ parentId?: string; // Optional parent hash
201
+ // ... custom fields
202
+ };
203
+
204
+ _signature: {
205
+ algorithm: string; // e.g., 'ml-dsa-87'
206
+ keyId: string; // Key identifier
207
+ publicKey: string; // Base64 public key (embedded for verification)
208
+ signature: string; // Base64 signature
209
+ timestamp: string; // When signed
210
+ };
211
+ }
212
+ ```
213
+
214
+ This format can be:
215
+ - Stored in databases (MongoDB, Postgres, etc.)
216
+ - Sent over HTTP/WebSocket
217
+ - Saved to files
218
+ - Verified years later
219
+
220
+ ---
221
+
222
+ ## Installation
223
+
224
+ ```bash
225
+ npm install @smartledger/envelope
226
+ ```
227
+
228
+ Requires:
229
+ - `@smartledger/keys` (automatically installed)
230
+ - `@smartledger/crypto` (automatically installed)
231
+
232
+ ---
233
+
234
+ ## Storage Examples
235
+
236
+ ### In-Memory (Default)
237
+
238
+ Keys are ephemeral - perfect for testing or short-lived processes:
239
+
240
+ ```typescript
241
+ const identity = await createAppIdentity({ name: 'TestApp' });
242
+ // Keys lost when process exits
243
+ ```
244
+
245
+ ### File-Based Storage
246
+
247
+ Implement your own `KeyStorage` class (see `@smartledger/crypto` for interface):
248
+
249
+ ```typescript
250
+ import { createKeySDK } from '@smartledger/keys';
251
+ import { KeyRegistry } from '@smartledger/crypto';
252
+ import { FileKeyStorage } from './storage'; // Your implementation
253
+
254
+ const sdk = createKeySDK({
255
+ keyRegistry: new KeyRegistry(new FileKeyStorage('./keys'))
256
+ });
257
+
258
+ const identity = await createAppIdentity({
259
+ name: 'MyApp',
260
+ sdk // Use your SDK with persistence
261
+ });
262
+ ```
263
+
264
+ See `/examples/file-storage/` for a complete implementation.
265
+
266
+ ### Database Storage
267
+
268
+ Similar pattern - implement `KeyStorage` for your database:
269
+
270
+ ```typescript
271
+ import { MongoKeyStorage } from './storage'; // Your implementation
272
+
273
+ const sdk = createKeySDK({
274
+ keyRegistry: new KeyRegistry(new MongoKeyStorage(mongoClient))
275
+ });
276
+
277
+ const identity = await createAppIdentity({ name: 'MyApp', sdk });
278
+ ```
279
+
280
+ See `/examples/mongodb-storage/` for a complete implementation.
281
+
282
+ ---
283
+
284
+ ## API Reference
285
+
286
+ ### High-Level API (Recommended)
287
+
288
+ #### `createAppIdentity(options)`
289
+
290
+ Create a signing identity:
291
+
292
+ ```typescript
293
+ const identity = await createAppIdentity({
294
+ name: 'MyApp', // Required: app/agent name
295
+ algorithm: 'ml-dsa-87', // Optional: 'ml-dsa-87' | 'bsv-ecdsa-secp256k1'
296
+ sdk: customSDK, // Optional: provide your own SDK with custom storage
297
+ existingKeyId: 'key-123' // Optional: use existing key
298
+ });
299
+ ```
300
+
301
+ #### `signJson(appName, data, options?)`
302
+
303
+ Convenience function for one-shot signing:
304
+
305
+ ```typescript
306
+ const signed = await signJson('MyApp', { message: "Hello!" });
307
+ ```
308
+
309
+ **Note:** Uses a global SDK instance. Keys persist across calls within the same process but are lost when the process exits.
310
+
311
+ #### `verifyJson(envelope)`
312
+
313
+ Convenience function for one-shot verification:
314
+
315
+ ```typescript
316
+ const result = await verifyJson(receivedEnvelope);
317
+ ```
318
+
319
+ Verifies envelopes created with `signJson()` in the same process.
320
+
321
+ ### Low-Level API (Advanced)
322
+
323
+ #### `createSignedEnvelope(sdk, keyId, payload, options)`
324
+
325
+ Full control over envelope creation:
326
+
327
+ ```typescript
328
+ import { createKeySDK } from '@smartledger/keys';
329
+ import { createSignedEnvelope } from '@smartledger/envelope';
330
+
331
+ const sdk = createKeySDK();
332
+ const key = await sdk.createKey('agent', { primarySignatureSuite: 'ml-dsa-87' });
333
+
334
+ const envelope = await createSignedEnvelope(sdk, key.meta.keyId, data, {
335
+ creator: 'my-agent',
336
+ contentType: 'custom-type',
337
+ metadata: { custom: 'fields' },
338
+ anchor: { chain: 'bitcoin', txId: '0x...', timestamp: '...' }
339
+ });
340
+ ```
341
+
342
+ #### `verifySignedEnvelope(sdk, envelope, options?)`
343
+
344
+ Full control over verification:
345
+
346
+ ```typescript
347
+ const result = await verifySignedEnvelope(sdk, envelope, {
348
+ maxAge: 86400000, // Reject if older than 24h
349
+ expectedCreator: 'alice', // Reject if not from alice
350
+ });
351
+ ```
352
+
353
+ #### Utility Functions
354
+
355
+ ```typescript
356
+ import {
357
+ extractPayload,
358
+ getEnvelopeMeta,
359
+ hasPQSignature,
360
+ hasAnchor,
361
+ createEnvelopeChain
362
+ } from '@smartledger/envelope';
363
+
364
+ // Extract payload without verification (use with caution)
365
+ const data = extractPayload(envelope);
366
+
367
+ // Get metadata
368
+ const meta = getEnvelopeMeta(envelope);
369
+
370
+ // Check capabilities
371
+ const hasPQ = hasPQSignature(envelope); // false (not implemented yet)
372
+ const hasChain = hasAnchor(envelope); // true if anchor present
373
+
374
+ // Create linked envelope
375
+ const child = await createEnvelopeChain(sdk, keyId, data, parent, options);
376
+ ```
377
+
378
+ ---
379
+
380
+ ## Philosophy
381
+
382
+ Digital content should answer four questions:
383
+
384
+ 1. **WHO** - Cryptographically proven creator
385
+ 2. **WHAT** - Content hash for tamper detection
386
+ 3. **WHEN** - Timestamp (ISO 8601)
387
+ 4. **HOW** - Algorithm + public key for verification
388
+
389
+ This envelope format provides all four. The format is simple and can be verified years later.
390
+
391
+ ---
392
+
393
+ ## Testing
394
+
395
+ ```bash
396
+ cd packages/envelope
397
+ npm test
398
+ ```
399
+
400
+ 78 tests covering:
401
+ - Envelope creation and verification
402
+ - Helper functions
403
+ - Type definitions
404
+ - Real-world scenarios (AI, blogs, microservices)
405
+ - Chain of custody
406
+ - Tampering detection
407
+
408
+ ---
409
+
410
+ ## Roadmap
411
+
412
+ ### Current (v1.0.0)
413
+ - ✅ SignedEnvelope format
414
+ - ✅ ML-DSA-87 and ECDSA support
415
+ - ✅ Chain of custody
416
+ - ✅ Simple API
417
+ - ✅ 78 comprehensive tests
418
+
419
+ ### Future
420
+ - [ ] Embedded public key verification (verify without SDK)
421
+ - [ ] JWS/JWT compatibility layer
422
+ - [ ] DID document generation
423
+ - [ ] Dual-signing (ECDSA + ML-DSA)
424
+ - [ ] On-chain anchor verification
425
+ - [ ] Browser bundle
426
+
427
+ ---
428
+
429
+ ## License
430
+
431
+ MIT - See [LICENSE](../../LICENSE)
432
+
433
+ ---
434
+
435
+ ## Author
436
+
437
+ **Gregory Ward (Codenlighten)**
438
+ Founder: [Codenlighten.org](https://codenlighten.org)
439
+ Co-founder & CTO: [SmartLedger.Technology](https://smartledger.technology)
440
+
441
+ ---
442
+
443
+ ## Related Packages
444
+
445
+ - [@smartledger/keys](../keys/) - Key management SDK
446
+ - [@smartledger/crypto](../crypto/) - Low-level cryptography primitives
447
+
448
+ ---
449
+
450
+ **Status:** 🚧 Alpha - API Stable, Features Complete, Tests Pending
451
+
452
+ **The cryptographic nervous system for verifiable AI.**
@@ -0,0 +1,70 @@
1
+ import type { KeySDK } from '@smartledger/keys';
2
+ import type { SignedEnvelope, CreateEnvelopeOptions, VerifyEnvelopeOptions, VerificationResult, EnvelopeMetadata } from './types.js';
3
+ /**
4
+ * Create a signed envelope from payload
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { createKeySDK } from '@smartledger/keys';
9
+ * import { createSignedEnvelope } from '@smartledger/envelope';
10
+ *
11
+ * const sdk = createKeySDK();
12
+ * const key = await sdk.createKey('my-agent', { primarySignatureSuite: 'ml-dsa-87' });
13
+ *
14
+ * const envelope = await createSignedEnvelope(
15
+ * sdk,
16
+ * key.meta.keyId,
17
+ * { message: "Hello, world!" },
18
+ * { creator: 'my-agent', contentType: 'greeting' }
19
+ * );
20
+ * ```
21
+ */
22
+ export declare function createSignedEnvelope<T>(sdk: KeySDK, keyId: string, payload: T, options: CreateEnvelopeOptions): Promise<SignedEnvelope<T>>;
23
+ /**
24
+ * Verify a signed envelope
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const result = await verifySignedEnvelope(sdk, envelope);
29
+ * if (result.valid) {
30
+ * console.log('Verified! Created by:', result.creator);
31
+ * console.log('Payload:', envelope.payload);
32
+ * }
33
+ * ```
34
+ */
35
+ export declare function verifySignedEnvelope<T>(sdk: KeySDK, envelope: SignedEnvelope<T>, options?: VerifyEnvelopeOptions): Promise<VerificationResult>;
36
+ /**
37
+ * Extract payload from envelope without verification
38
+ * Use only when verification was done previously
39
+ */
40
+ export declare function extractPayload<T>(envelope: SignedEnvelope<T>): T;
41
+ /**
42
+ * Get envelope metadata
43
+ */
44
+ export declare function getEnvelopeMeta<T>(envelope: SignedEnvelope<T>): EnvelopeMetadata;
45
+ /**
46
+ * Check if envelope has PQ signature
47
+ */
48
+ export declare function hasPQSignature<T>(envelope: SignedEnvelope<T>): boolean;
49
+ /**
50
+ * Check if envelope has on-chain anchor
51
+ */
52
+ export declare function hasAnchor<T>(envelope: SignedEnvelope<T>): boolean;
53
+ /**
54
+ * Create a chain of custody by linking envelopes
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const original = await createSignedEnvelope(sdk, keyId, data, { creator: 'alice' });
59
+ * const updated = await createEnvelopeChain(
60
+ * sdk,
61
+ * keyId,
62
+ * updatedData,
63
+ * original,
64
+ * { creator: 'bob', contentType: 'revision' }
65
+ * );
66
+ * // updated.meta.parentId === hash(original)
67
+ * ```
68
+ */
69
+ export declare function createEnvelopeChain<T>(sdk: KeySDK, keyId: string, payload: T, parentEnvelope: SignedEnvelope<any>, options: Omit<CreateEnvelopeOptions, 'parentId'>): Promise<SignedEnvelope<T>>;
70
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAEjB,MAAM,YAAY,CAAC;AAIpB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,EACV,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAmD5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,EAC3B,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,kBAAkB,CAAC,CAsE7B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAEhE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAEhF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAEtE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAEjE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,EACV,cAAc,EAAE,cAAc,CAAC,GAAG,CAAC,EACnC,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,GAC/C,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAW5B"}