@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 +23 -0
- package/README.md +452 -0
- package/dist/cjs/envelope.d.ts +70 -0
- package/dist/cjs/envelope.d.ts.map +1 -0
- package/dist/cjs/envelope.js +191 -0
- package/dist/cjs/envelope.js.map +1 -0
- package/dist/cjs/helpers.d.ts +133 -0
- package/dist/cjs/helpers.d.ts.map +1 -0
- package/dist/cjs/helpers.js +159 -0
- package/dist/cjs/helpers.js.map +1 -0
- package/dist/cjs/index.d.ts +12 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +11 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/types.d.ts +151 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +20 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/envelope.d.ts +70 -0
- package/dist/esm/envelope.d.ts.map +1 -0
- package/dist/esm/envelope.js +191 -0
- package/dist/esm/envelope.js.map +1 -0
- package/dist/esm/helpers.d.ts +133 -0
- package/dist/esm/helpers.d.ts.map +1 -0
- package/dist/esm/helpers.js +159 -0
- package/dist/esm/helpers.js.map +1 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/types.d.ts +151 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +20 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
const ENVELOPE_VERSION = '1.0.0';
|
|
2
|
+
/**
|
|
3
|
+
* Create a signed envelope from payload
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { createKeySDK } from '@smartledger/keys';
|
|
8
|
+
* import { createSignedEnvelope } from '@smartledger/envelope';
|
|
9
|
+
*
|
|
10
|
+
* const sdk = createKeySDK();
|
|
11
|
+
* const key = await sdk.createKey('my-agent', { primarySignatureSuite: 'ml-dsa-87' });
|
|
12
|
+
*
|
|
13
|
+
* const envelope = await createSignedEnvelope(
|
|
14
|
+
* sdk,
|
|
15
|
+
* key.meta.keyId,
|
|
16
|
+
* { message: "Hello, world!" },
|
|
17
|
+
* { creator: 'my-agent', contentType: 'greeting' }
|
|
18
|
+
* );
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export async function createSignedEnvelope(sdk, keyId, payload, options) {
|
|
22
|
+
const now = new Date().toISOString();
|
|
23
|
+
// Build metadata
|
|
24
|
+
const meta = {
|
|
25
|
+
version: ENVELOPE_VERSION,
|
|
26
|
+
creator: options.creator,
|
|
27
|
+
creatorType: options.creatorType,
|
|
28
|
+
createdAt: now,
|
|
29
|
+
contentType: options.contentType,
|
|
30
|
+
anchor: options.anchor,
|
|
31
|
+
parentId: options.parentId,
|
|
32
|
+
...options.metadata,
|
|
33
|
+
};
|
|
34
|
+
// Create canonical payload to sign
|
|
35
|
+
const canonical = {
|
|
36
|
+
payload,
|
|
37
|
+
meta,
|
|
38
|
+
};
|
|
39
|
+
const message = new TextEncoder().encode(JSON.stringify(canonical));
|
|
40
|
+
// Sign with primary key
|
|
41
|
+
const signature = await sdk.signWithKey(keyId, message);
|
|
42
|
+
const key = await sdk.getKey(keyId);
|
|
43
|
+
if (!key) {
|
|
44
|
+
throw new Error(`Key ${keyId} not found`);
|
|
45
|
+
}
|
|
46
|
+
const signatureMetadata = {
|
|
47
|
+
algorithm: key.meta.suiteId,
|
|
48
|
+
keyId,
|
|
49
|
+
publicKey: Buffer.from(key.publicKey).toString('base64'),
|
|
50
|
+
signature: Buffer.from(signature).toString('base64'),
|
|
51
|
+
timestamp: now,
|
|
52
|
+
};
|
|
53
|
+
// Optional: dual-sign with PQ if requested and available
|
|
54
|
+
if (options.dualSign) {
|
|
55
|
+
// Check if suite has PQ capability or if there's a secondary suite
|
|
56
|
+
// For now, just document the pattern - implementation would check
|
|
57
|
+
// if key has a secondary PQ suite and sign with that too
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
payload,
|
|
61
|
+
meta,
|
|
62
|
+
_signature: signatureMetadata,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Verify a signed envelope
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const result = await verifySignedEnvelope(sdk, envelope);
|
|
71
|
+
* if (result.valid) {
|
|
72
|
+
* console.log('Verified! Created by:', result.creator);
|
|
73
|
+
* console.log('Payload:', envelope.payload);
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export async function verifySignedEnvelope(sdk, envelope, options = {}) {
|
|
78
|
+
try {
|
|
79
|
+
// Check age if maxAge specified
|
|
80
|
+
if (options.maxAge) {
|
|
81
|
+
const signatureTime = new Date(envelope._signature.timestamp).getTime();
|
|
82
|
+
const age = Date.now() - signatureTime;
|
|
83
|
+
if (age > options.maxAge) {
|
|
84
|
+
return {
|
|
85
|
+
valid: false,
|
|
86
|
+
error: `Signature too old: ${age}ms > ${options.maxAge}ms`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Check expected creator if specified
|
|
91
|
+
if (options.expectedCreator && envelope.meta.creator !== options.expectedCreator) {
|
|
92
|
+
return {
|
|
93
|
+
valid: false,
|
|
94
|
+
error: `Unexpected creator: ${envelope.meta.creator} !== ${options.expectedCreator}`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// Reconstruct canonical message
|
|
98
|
+
const canonical = {
|
|
99
|
+
payload: envelope.payload,
|
|
100
|
+
meta: envelope.meta,
|
|
101
|
+
};
|
|
102
|
+
const message = new TextEncoder().encode(JSON.stringify(canonical));
|
|
103
|
+
const signature = Buffer.from(envelope._signature.signature, 'base64');
|
|
104
|
+
// Verify signature
|
|
105
|
+
const keyId = envelope._signature.keyId;
|
|
106
|
+
if (!keyId) {
|
|
107
|
+
return {
|
|
108
|
+
valid: false,
|
|
109
|
+
error: 'No keyId in signature metadata',
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const valid = await sdk.verifySignature(keyId, message, signature);
|
|
113
|
+
if (!valid) {
|
|
114
|
+
return {
|
|
115
|
+
valid: false,
|
|
116
|
+
error: 'Signature verification failed',
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Verify PQ signature if present and requested
|
|
120
|
+
let verified = 'primary';
|
|
121
|
+
if (options.verifyPQ && envelope._signature.pqSignature) {
|
|
122
|
+
// Would verify PQ signature here
|
|
123
|
+
// For now, just document the pattern
|
|
124
|
+
verified = 'both';
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
valid: true,
|
|
128
|
+
verified,
|
|
129
|
+
creator: envelope.meta.creator,
|
|
130
|
+
timestamp: envelope._signature.timestamp,
|
|
131
|
+
contentMatch: true,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
return {
|
|
136
|
+
valid: false,
|
|
137
|
+
error: error instanceof Error ? error.message : String(error),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Extract payload from envelope without verification
|
|
143
|
+
* Use only when verification was done previously
|
|
144
|
+
*/
|
|
145
|
+
export function extractPayload(envelope) {
|
|
146
|
+
return envelope.payload;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get envelope metadata
|
|
150
|
+
*/
|
|
151
|
+
export function getEnvelopeMeta(envelope) {
|
|
152
|
+
return envelope.meta;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Check if envelope has PQ signature
|
|
156
|
+
*/
|
|
157
|
+
export function hasPQSignature(envelope) {
|
|
158
|
+
return !!envelope._signature.pqSignature;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Check if envelope has on-chain anchor
|
|
162
|
+
*/
|
|
163
|
+
export function hasAnchor(envelope) {
|
|
164
|
+
return !!envelope.meta.anchor;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Create a chain of custody by linking envelopes
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* const original = await createSignedEnvelope(sdk, keyId, data, { creator: 'alice' });
|
|
172
|
+
* const updated = await createEnvelopeChain(
|
|
173
|
+
* sdk,
|
|
174
|
+
* keyId,
|
|
175
|
+
* updatedData,
|
|
176
|
+
* original,
|
|
177
|
+
* { creator: 'bob', contentType: 'revision' }
|
|
178
|
+
* );
|
|
179
|
+
* // updated.meta.parentId === hash(original)
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
export async function createEnvelopeChain(sdk, keyId, payload, parentEnvelope, options) {
|
|
183
|
+
// Create a hash of parent envelope as parentId
|
|
184
|
+
const parentJson = JSON.stringify(parentEnvelope);
|
|
185
|
+
const parentHash = Buffer.from(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(parentJson))).toString('hex');
|
|
186
|
+
return createSignedEnvelope(sdk, keyId, payload, {
|
|
187
|
+
...options,
|
|
188
|
+
parentId: parentHash,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { type KeySDK } from '@smartledger/keys';
|
|
2
|
+
import type { SignedEnvelope, VerificationResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* High-level app identity interface
|
|
5
|
+
* This is the "1-2 line setup" API that makes adoption trivial
|
|
6
|
+
*/
|
|
7
|
+
export interface AppIdentity {
|
|
8
|
+
/** App/agent name */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Key ID being used */
|
|
11
|
+
keyId: string;
|
|
12
|
+
/** Sign any JSON-serializable data */
|
|
13
|
+
signJson<T>(data: T, options?: {
|
|
14
|
+
contentType?: string;
|
|
15
|
+
}): Promise<SignedEnvelope<T>>;
|
|
16
|
+
/** Verify any signed envelope */
|
|
17
|
+
verifyJson<T>(envelope: SignedEnvelope<T>): Promise<VerificationResult>;
|
|
18
|
+
/** Get the underlying SDK (for advanced usage) */
|
|
19
|
+
getSDK(): KeySDK;
|
|
20
|
+
/** Get public key for sharing */
|
|
21
|
+
getPublicKey(): Promise<Uint8Array>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create an app identity in 1-2 lines
|
|
25
|
+
*
|
|
26
|
+
* This is the "killer API" that makes people go: "Oh, I get it."
|
|
27
|
+
*
|
|
28
|
+
* Creates an in-memory identity for signing/verification. Keys are ephemeral by default.
|
|
29
|
+
* For persistence, see examples/file-storage or provide your own KeySDK with custom storage.
|
|
30
|
+
*
|
|
31
|
+
* @example Dead simple setup
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { createAppIdentity } from '@smartledger/envelope';
|
|
34
|
+
*
|
|
35
|
+
* // That's it. You're ready to sign things (in-memory).
|
|
36
|
+
* const identity = await createAppIdentity({ name: 'MyCoolApp' });
|
|
37
|
+
*
|
|
38
|
+
* // Sign anything
|
|
39
|
+
* const signed = await identity.signJson({ message: "Hello, world!" });
|
|
40
|
+
*
|
|
41
|
+
* // Verify anything
|
|
42
|
+
* const result = await identity.verifyJson(signed);
|
|
43
|
+
* console.log('Valid:', result.valid);
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @example Use existing SDK with custom storage
|
|
47
|
+
* ```typescript
|
|
48
|
+
* import { createKeySDK } from '@smartledger/keys';
|
|
49
|
+
* import { FileKeyStorage } from './storage'; // See examples/
|
|
50
|
+
*
|
|
51
|
+
* const sdk = createKeySDK({ storage: new FileKeyStorage('./keys') });
|
|
52
|
+
* const key = await sdk.createKey('MyCoolApp', { primarySignatureSuite: 'ml-dsa-87' });
|
|
53
|
+
*
|
|
54
|
+
* const identity = await createAppIdentity({
|
|
55
|
+
* name: 'MyCoolApp',
|
|
56
|
+
* sdk, // Use your SDK with persistence
|
|
57
|
+
* existingKeyId: key.meta.keyId
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @example Sign AI responses
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const identity = await createAppIdentity({ name: 'MyAI' });
|
|
64
|
+
*
|
|
65
|
+
* const response = await openai.chat.completions.create({
|
|
66
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* const signed = await identity.signJson(response, {
|
|
70
|
+
* contentType: 'ai-response'
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* // Now you have cryptographic proof of what your AI said and when
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @example Verify third-party content
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const theirIdentity = await createAppIdentity({
|
|
79
|
+
* name: 'TheirApp',
|
|
80
|
+
* existingKeyId: 'their-public-key-id'
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* const result = await theirIdentity.verifyJson(receivedEnvelope);
|
|
84
|
+
* if (result.valid) {
|
|
85
|
+
* console.log('Verified from:', result.creator);
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function createAppIdentity(options: {
|
|
90
|
+
/** App/agent name */
|
|
91
|
+
name: string;
|
|
92
|
+
/** Signature algorithm (default: 'ml-dsa-87') */
|
|
93
|
+
algorithm?: 'ml-dsa-87' | 'bsv-ecdsa-secp256k1';
|
|
94
|
+
/** Provide your own SDK (e.g., with custom storage) */
|
|
95
|
+
sdk?: KeySDK;
|
|
96
|
+
/** Use existing key ID instead of creating new */
|
|
97
|
+
existingKeyId?: string;
|
|
98
|
+
}): Promise<AppIdentity>;
|
|
99
|
+
/**
|
|
100
|
+
* Convenience: Sign JSON and return envelope in one call
|
|
101
|
+
* For when you don't need to keep the identity around
|
|
102
|
+
*
|
|
103
|
+
* Uses a singleton SDK instance so keys persist across calls.
|
|
104
|
+
* This allows verifyJson() to verify envelopes from signJson().
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* import { signJson } from '@smartledger/envelope';
|
|
109
|
+
*
|
|
110
|
+
* const signed = await signJson('MyApp', { message: "Hello!" });
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export declare function signJson<T>(appName: string, data: T, options?: {
|
|
114
|
+
algorithm?: 'ml-dsa-87' | 'bsv-ecdsa-secp256k1';
|
|
115
|
+
contentType?: string;
|
|
116
|
+
}): Promise<SignedEnvelope<T>>;
|
|
117
|
+
/**
|
|
118
|
+
* Convenience: Verify JSON envelope in one call
|
|
119
|
+
*
|
|
120
|
+
* Uses a singleton SDK instance to verify envelopes created with signJson().
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* import { verifyJson } from '@smartledger/envelope';
|
|
125
|
+
*
|
|
126
|
+
* const result = await verifyJson(receivedEnvelope);
|
|
127
|
+
* if (result.valid) {
|
|
128
|
+
* console.log('Payload:', receivedEnvelope.payload);
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function verifyJson<T>(envelope: SignedEnvelope<T>): Promise<VerificationResult>;
|
|
133
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAcrE;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IAEb,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IAEd,sCAAsC;IACtC,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAErF,iCAAiC;IACjC,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAExE,kDAAkD;IAClD,MAAM,IAAI,MAAM,CAAC;IAEjB,iCAAiC;IACjC,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IAEb,iDAAiD;IACjD,SAAS,CAAC,EAAE,WAAW,GAAG,qBAAqB,CAAC;IAEhD,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,kDAAkD;IAClD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,WAAW,CAAC,CA8CvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,CAAC,EACP,OAAO,CAAC,EAAE;IACR,SAAS,CAAC,EAAE,WAAW,GAAG,qBAAqB,CAAC;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACA,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAQ5B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,kBAAkB,CAAC,CAG7B"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { createKeySDK } from '@smartledger/keys';
|
|
2
|
+
import { createSignedEnvelope, verifySignedEnvelope } from './envelope.js';
|
|
3
|
+
// Singleton SDK for convenience functions
|
|
4
|
+
// This allows signJson() and verifyJson() to work across calls
|
|
5
|
+
let _globalSDK = null;
|
|
6
|
+
function getGlobalSDK() {
|
|
7
|
+
if (!_globalSDK) {
|
|
8
|
+
_globalSDK = createKeySDK();
|
|
9
|
+
}
|
|
10
|
+
return _globalSDK;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Create an app identity in 1-2 lines
|
|
14
|
+
*
|
|
15
|
+
* This is the "killer API" that makes people go: "Oh, I get it."
|
|
16
|
+
*
|
|
17
|
+
* Creates an in-memory identity for signing/verification. Keys are ephemeral by default.
|
|
18
|
+
* For persistence, see examples/file-storage or provide your own KeySDK with custom storage.
|
|
19
|
+
*
|
|
20
|
+
* @example Dead simple setup
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { createAppIdentity } from '@smartledger/envelope';
|
|
23
|
+
*
|
|
24
|
+
* // That's it. You're ready to sign things (in-memory).
|
|
25
|
+
* const identity = await createAppIdentity({ name: 'MyCoolApp' });
|
|
26
|
+
*
|
|
27
|
+
* // Sign anything
|
|
28
|
+
* const signed = await identity.signJson({ message: "Hello, world!" });
|
|
29
|
+
*
|
|
30
|
+
* // Verify anything
|
|
31
|
+
* const result = await identity.verifyJson(signed);
|
|
32
|
+
* console.log('Valid:', result.valid);
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example Use existing SDK with custom storage
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { createKeySDK } from '@smartledger/keys';
|
|
38
|
+
* import { FileKeyStorage } from './storage'; // See examples/
|
|
39
|
+
*
|
|
40
|
+
* const sdk = createKeySDK({ storage: new FileKeyStorage('./keys') });
|
|
41
|
+
* const key = await sdk.createKey('MyCoolApp', { primarySignatureSuite: 'ml-dsa-87' });
|
|
42
|
+
*
|
|
43
|
+
* const identity = await createAppIdentity({
|
|
44
|
+
* name: 'MyCoolApp',
|
|
45
|
+
* sdk, // Use your SDK with persistence
|
|
46
|
+
* existingKeyId: key.meta.keyId
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example Sign AI responses
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const identity = await createAppIdentity({ name: 'MyAI' });
|
|
53
|
+
*
|
|
54
|
+
* const response = await openai.chat.completions.create({
|
|
55
|
+
* messages: [{ role: 'user', content: 'Hello!' }]
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* const signed = await identity.signJson(response, {
|
|
59
|
+
* contentType: 'ai-response'
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* // Now you have cryptographic proof of what your AI said and when
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example Verify third-party content
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const theirIdentity = await createAppIdentity({
|
|
68
|
+
* name: 'TheirApp',
|
|
69
|
+
* existingKeyId: 'their-public-key-id'
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* const result = await theirIdentity.verifyJson(receivedEnvelope);
|
|
73
|
+
* if (result.valid) {
|
|
74
|
+
* console.log('Verified from:', result.creator);
|
|
75
|
+
* }
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export async function createAppIdentity(options) {
|
|
79
|
+
const sdk = options.sdk || createKeySDK();
|
|
80
|
+
const algorithm = options.algorithm || 'ml-dsa-87';
|
|
81
|
+
// Create or use existing key
|
|
82
|
+
let keyId;
|
|
83
|
+
if (options.existingKeyId) {
|
|
84
|
+
keyId = options.existingKeyId;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const key = await sdk.createKey(options.name, {
|
|
88
|
+
primarySignatureSuite: algorithm,
|
|
89
|
+
});
|
|
90
|
+
keyId = key.meta.keyId;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
name: options.name,
|
|
94
|
+
keyId,
|
|
95
|
+
async signJson(data, opts) {
|
|
96
|
+
return createSignedEnvelope(sdk, keyId, data, {
|
|
97
|
+
creator: options.name,
|
|
98
|
+
creatorType: 'service',
|
|
99
|
+
contentType: opts?.contentType,
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
async verifyJson(envelope) {
|
|
103
|
+
return verifySignedEnvelope(sdk, envelope);
|
|
104
|
+
},
|
|
105
|
+
getSDK() {
|
|
106
|
+
return sdk;
|
|
107
|
+
},
|
|
108
|
+
async getPublicKey() {
|
|
109
|
+
const key = await sdk.getKey(keyId);
|
|
110
|
+
if (!key) {
|
|
111
|
+
throw new Error(`Key ${keyId} not found`);
|
|
112
|
+
}
|
|
113
|
+
return key.publicKey;
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Convenience: Sign JSON and return envelope in one call
|
|
119
|
+
* For when you don't need to keep the identity around
|
|
120
|
+
*
|
|
121
|
+
* Uses a singleton SDK instance so keys persist across calls.
|
|
122
|
+
* This allows verifyJson() to verify envelopes from signJson().
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* import { signJson } from '@smartledger/envelope';
|
|
127
|
+
*
|
|
128
|
+
* const signed = await signJson('MyApp', { message: "Hello!" });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export async function signJson(appName, data, options) {
|
|
132
|
+
const sdk = getGlobalSDK();
|
|
133
|
+
const identity = await createAppIdentity({
|
|
134
|
+
name: appName,
|
|
135
|
+
algorithm: options?.algorithm,
|
|
136
|
+
sdk,
|
|
137
|
+
});
|
|
138
|
+
return identity.signJson(data, { contentType: options?.contentType });
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Convenience: Verify JSON envelope in one call
|
|
142
|
+
*
|
|
143
|
+
* Uses a singleton SDK instance to verify envelopes created with signJson().
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* import { verifyJson } from '@smartledger/envelope';
|
|
148
|
+
*
|
|
149
|
+
* const result = await verifyJson(receivedEnvelope);
|
|
150
|
+
* if (result.valid) {
|
|
151
|
+
* console.log('Payload:', receivedEnvelope.payload);
|
|
152
|
+
* }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export async function verifyJson(envelope) {
|
|
156
|
+
const sdk = getGlobalSDK();
|
|
157
|
+
return verifySignedEnvelope(sdk, envelope);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE3E,0CAA0C;AAC1C,+DAA+D;AAC/D,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC,SAAS,YAAY;IACnB,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,UAAU,GAAG,YAAY,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAYvC;IACC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,YAAY,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,WAAW,CAAC;IAEnD,6BAA6B;IAC7B,IAAI,KAAa,CAAC;IAClB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE;YAC5C,qBAAqB,EAAE,SAAS;SACjC,CAAC,CAAC;QACH,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK;QAEL,KAAK,CAAC,QAAQ,CACZ,IAAO,EACP,IAA+B;YAE/B,OAAO,oBAAoB,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;gBAC5C,OAAO,EAAE,OAAO,CAAC,IAAI;gBACrB,WAAW,EAAE,SAAS;gBACtB,WAAW,EAAE,IAAI,EAAE,WAAW;aAC/B,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,UAAU,CAAI,QAA2B;YAC7C,OAAO,oBAAoB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM;YACJ,OAAO,GAAG,CAAC;QACb,CAAC;QAED,KAAK,CAAC,YAAY;YAChB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC;YAC5C,CAAC;YACD,OAAO,GAAG,CAAC,SAAS,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAe,EACf,IAAO,EACP,OAGC;IAED,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC;QACvC,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,GAAG;KACJ,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAA2B;IAE3B,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,OAAO,oBAAoB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @smartledger/envelope - Canonical SignedEnvelope for verifiable content
|
|
3
|
+
*
|
|
4
|
+
* The standard way to wrap any content with cryptographic verification.
|
|
5
|
+
*/
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
export * from './envelope.js';
|
|
8
|
+
export * from './helpers.js';
|
|
9
|
+
export type { SignedEnvelope, SignatureMetadata, EnvelopeMetadata, CreateEnvelopeOptions, VerifyEnvelopeOptions, VerificationResult, } from './types.js';
|
|
10
|
+
export { createSignedEnvelope, verifySignedEnvelope, extractPayload, getEnvelopeMeta, hasPQSignature, hasAnchor, createEnvelopeChain, } from './envelope.js';
|
|
11
|
+
export { createAppIdentity, type AppIdentity, } from './helpers.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAG7B,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,cAAc,EACd,SAAS,EACT,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @smartledger/envelope - Canonical SignedEnvelope for verifiable content
|
|
3
|
+
*
|
|
4
|
+
* The standard way to wrap any content with cryptographic verification.
|
|
5
|
+
*/
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
export * from './envelope.js';
|
|
8
|
+
export * from './helpers.js';
|
|
9
|
+
export { createSignedEnvelope, verifySignedEnvelope, extractPayload, getEnvelopeMeta, hasPQSignature, hasAnchor, createEnvelopeChain, } from './envelope.js';
|
|
10
|
+
export { createAppIdentity, } from './helpers.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAY7B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,cAAc,EACd,SAAS,EACT,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,iBAAiB,GAElB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SignedEnvelope - Canonical schema for verifiable AI outputs and content provenance
|
|
3
|
+
*
|
|
4
|
+
* This is the standard envelope format for any content that needs cryptographic verification:
|
|
5
|
+
* - AI-generated responses
|
|
6
|
+
* - User submissions
|
|
7
|
+
* - Agent communications
|
|
8
|
+
* - Contract artifacts
|
|
9
|
+
* - Audit logs
|
|
10
|
+
*
|
|
11
|
+
* Philosophy: Every piece of digital content should be able to answer:
|
|
12
|
+
* - WHO created it (cryptographically proven identity)
|
|
13
|
+
* - WHAT they created (content hash)
|
|
14
|
+
* - WHEN they created it (timestamp)
|
|
15
|
+
* - HOW to verify it (algorithm + public key)
|
|
16
|
+
*
|
|
17
|
+
* This envelope can be verified in 2025, 2045, or 2075.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Core signature metadata
|
|
21
|
+
*/
|
|
22
|
+
export interface SignatureMetadata {
|
|
23
|
+
/** Signature suite ID (e.g., 'bsv-ecdsa-secp256k1', 'ml-dsa-87') */
|
|
24
|
+
algorithm: string;
|
|
25
|
+
/** Public key or keyId for verification */
|
|
26
|
+
publicKey?: string;
|
|
27
|
+
keyId?: string;
|
|
28
|
+
/** Base64-encoded signature */
|
|
29
|
+
signature: string;
|
|
30
|
+
/** ISO 8601 timestamp when signature was created */
|
|
31
|
+
timestamp: string;
|
|
32
|
+
/** Optional post-quantum signature for dual-signing */
|
|
33
|
+
pqSignature?: {
|
|
34
|
+
algorithm: string;
|
|
35
|
+
publicKey?: string;
|
|
36
|
+
keyId?: string;
|
|
37
|
+
signature: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Metadata about the envelope and its context
|
|
42
|
+
*/
|
|
43
|
+
export interface EnvelopeMetadata {
|
|
44
|
+
/** Version of the envelope schema (semver) */
|
|
45
|
+
version: string;
|
|
46
|
+
/** Who/what created this (agentId, userId, appName, etc.) */
|
|
47
|
+
creator: string;
|
|
48
|
+
/** Optional creator type for context */
|
|
49
|
+
creatorType?: 'human' | 'agent' | 'service' | 'dao';
|
|
50
|
+
/** ISO 8601 creation timestamp */
|
|
51
|
+
createdAt: string;
|
|
52
|
+
/** Content type hint (e.g., 'ai-response', 'blog-post', 'contract') */
|
|
53
|
+
contentType?: string;
|
|
54
|
+
/** Optional on-chain anchor reference */
|
|
55
|
+
anchor?: {
|
|
56
|
+
/** Blockchain/ledger identifier */
|
|
57
|
+
chain: string;
|
|
58
|
+
/** Transaction ID or block reference */
|
|
59
|
+
txId: string;
|
|
60
|
+
/** Timestamp of on-chain commitment */
|
|
61
|
+
timestamp: string;
|
|
62
|
+
};
|
|
63
|
+
/** Optional parent envelope reference (for chains of custody) */
|
|
64
|
+
parentId?: string;
|
|
65
|
+
/** Application-specific metadata */
|
|
66
|
+
[key: string]: any;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The canonical SignedEnvelope structure
|
|
70
|
+
*
|
|
71
|
+
* @example Basic usage
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const envelope: SignedEnvelope<MyData> = {
|
|
74
|
+
* payload: { message: "Hello, verifiable world!" },
|
|
75
|
+
* meta: {
|
|
76
|
+
* version: "1.0.0",
|
|
77
|
+
* creator: "my-agent",
|
|
78
|
+
* createdAt: new Date().toISOString(),
|
|
79
|
+
* contentType: "ai-response"
|
|
80
|
+
* },
|
|
81
|
+
* _signature: {
|
|
82
|
+
* algorithm: "ml-dsa-87",
|
|
83
|
+
* keyId: "agent-key-001",
|
|
84
|
+
* signature: "base64...",
|
|
85
|
+
* timestamp: new Date().toISOString()
|
|
86
|
+
* }
|
|
87
|
+
* };
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export interface SignedEnvelope<T = any> {
|
|
91
|
+
/** The actual content being signed */
|
|
92
|
+
payload: T;
|
|
93
|
+
/** Metadata about the envelope */
|
|
94
|
+
meta: EnvelopeMetadata;
|
|
95
|
+
/** Cryptographic signature and verification data */
|
|
96
|
+
_signature: SignatureMetadata;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Options for creating a signed envelope
|
|
100
|
+
*/
|
|
101
|
+
export interface CreateEnvelopeOptions {
|
|
102
|
+
/** Creator identifier (agentId, userId, etc.) */
|
|
103
|
+
creator: string;
|
|
104
|
+
/** Optional creator type */
|
|
105
|
+
creatorType?: 'human' | 'agent' | 'service' | 'dao';
|
|
106
|
+
/** Optional content type hint */
|
|
107
|
+
contentType?: string;
|
|
108
|
+
/** Optional parent envelope ID for chains of custody */
|
|
109
|
+
parentId?: string;
|
|
110
|
+
/** Whether to include post-quantum signature */
|
|
111
|
+
dualSign?: boolean;
|
|
112
|
+
/** Optional on-chain anchor info */
|
|
113
|
+
anchor?: {
|
|
114
|
+
chain: string;
|
|
115
|
+
txId: string;
|
|
116
|
+
timestamp: string;
|
|
117
|
+
};
|
|
118
|
+
/** Additional metadata */
|
|
119
|
+
metadata?: Record<string, any>;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Verification result
|
|
123
|
+
*/
|
|
124
|
+
export interface VerificationResult {
|
|
125
|
+
/** Whether the signature is valid */
|
|
126
|
+
valid: boolean;
|
|
127
|
+
/** Which signature was verified ('primary' | 'pq' | 'both') */
|
|
128
|
+
verified?: 'primary' | 'pq' | 'both';
|
|
129
|
+
/** Error message if verification failed */
|
|
130
|
+
error?: string;
|
|
131
|
+
/** The creator from the envelope metadata */
|
|
132
|
+
creator?: string;
|
|
133
|
+
/** Timestamp from the signature */
|
|
134
|
+
timestamp?: string;
|
|
135
|
+
/** Whether content hash matches */
|
|
136
|
+
contentMatch?: boolean;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Options for verifying an envelope
|
|
140
|
+
*/
|
|
141
|
+
export interface VerifyEnvelopeOptions {
|
|
142
|
+
/** Whether to verify PQ signature if present */
|
|
143
|
+
verifyPQ?: boolean;
|
|
144
|
+
/** Maximum age in milliseconds (rejects if older) */
|
|
145
|
+
maxAge?: number;
|
|
146
|
+
/** Expected creator (rejects if different) */
|
|
147
|
+
expectedCreator?: string;
|
|
148
|
+
/** Whether to verify on-chain anchor if present */
|
|
149
|
+
verifyAnchor?: boolean;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=types.d.ts.map
|