@smartledger/envelope
v1.0.0
Published
Canonical SignedResponse/SignedEnvelope schema for verifiable AI outputs and content provenance
Maintainers
Readme
@smartledger/envelope
Simple, verifiable content signing for any application.
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.
Quick Start
import { createAppIdentity } from '@smartledger/envelope';
// Create an identity (in-memory keys)
const identity = await createAppIdentity({ name: 'MyCoolApp' });
// Sign anything
const signed = await identity.signJson({ message: "Hello, world!" });
// Verify anything
const result = await identity.verifyJson(signed);
console.log('Valid:', result.valid); // trueKeys are ephemeral (in-memory) by default. For persistence, see Storage Examples below.
What It Does
This package provides:
- SignedEnvelope format - A standard schema for signed content
- Simple API - One-line setup, easy signing/verification
- Post-quantum support - ML-DSA-87 (NIST FIPS 204) by default
- Flexible - Works with any JSON-serializable data
What It Doesn't Do
This is a primitive, not a complete application. It doesn't include:
- ❌ Persistent key storage (but see examples for how to add it)
- ❌ DID generation or resolution
- ❌ Verifiable Credentials
- ❌ Blockchain integration
- ❌ KYC or identity verification
Those features belong in your application or separate packages. This library gives you the cryptographic foundation to build them.
Use Cases
Verifiable AI Responses
import OpenAI from 'openai';
const identity = await createAppIdentity({ name: 'MyAI' });
const openai = new OpenAI();
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Explain quantum computing' }]
});
// Sign the AI response
const signed = await identity.signJson(response, {
contentType: 'ai-response'
});
// Now you have cryptographic proof of what your AI said and whenSigned Content / Blog Posts
const identity = await createAppIdentity({ name: 'MyBlog' });
const post = {
title: "Why Cryptography Matters",
content: "...",
author: "Alice",
};
const signedPost = await identity.signJson(post, {
contentType: 'blog-post'
});
// Readers can verify authenticity
// Authors can't deny writing it
// Editors can't change it without detectionMicroservice Authentication
// Service A signs requests
const serviceA = await createAppIdentity({ name: 'ServiceA' });
const request = await serviceA.signJson({
action: 'process-payment',
amount: 100,
});
// Service B verifies before processing
const result = await serviceB.verifyJson(request);
if (result.valid && result.creator === 'ServiceA') {
// Process - we know it's really from ServiceA
}Audit Trails with Chain of Custody
import { createEnvelopeChain } from '@smartledger/envelope';
const original = await identity.signJson(
{ status: 'draft', content: '...' }
);
// Link revision to original
const revision = await createEnvelopeChain(
identity.getSDK(),
identity.keyId,
{ status: 'reviewed', content: '...' },
original,
{ creator: 'reviewer' }
);
// revision.meta.parentId === hash(original)
// Full provenance chain preservedFeatures
🔐 Post-Quantum Ready
Uses ML-DSA-87 (NIST FIPS 204) by default - quantum-resistant signatures:
const identity = await createAppIdentity({
name: 'MyApp',
algorithm: 'ml-dsa-87' // Default
});Or use ECDSA for Bitcoin compatibility:
const identity = await createAppIdentity({
name: 'MyApp',
algorithm: 'bsv-ecdsa-secp256k1'
});📜 Chain of Custody
Link envelopes to create verifiable revision chains:
const updated = await createEnvelopeChain(
sdk, keyId, updatedData, originalEnvelope,
{ creator: 'editor' }
);
// updated.meta.parentId === hash(originalEnvelope)🔗 Extensible Metadata
Add custom metadata for your use case:
const signed = await createSignedEnvelope(sdk, keyId, data, {
creator: 'MyApp',
contentType: 'invoice',
metadata: {
invoiceNumber: 'INV-001',
customField: 'anything'
}
});Envelope Format
The SignedEnvelope is a simple, universal format:
interface SignedEnvelope<T> {
payload: T; // Your actual data
meta: {
version: string; // Schema version
creator: string; // Who created it
createdAt: string; // ISO 8601 timestamp
contentType?: string; // Optional type hint
parentId?: string; // Optional parent hash
// ... custom fields
};
_signature: {
algorithm: string; // e.g., 'ml-dsa-87'
keyId: string; // Key identifier
publicKey: string; // Base64 public key (embedded for verification)
signature: string; // Base64 signature
timestamp: string; // When signed
};
}This format can be:
- Stored in databases (MongoDB, Postgres, etc.)
- Sent over HTTP/WebSocket
- Saved to files
- Verified years later
Installation
npm install @smartledger/envelopeRequires:
@smartledger/keys(automatically installed)@smartledger/crypto(automatically installed)
Storage Examples
In-Memory (Default)
Keys are ephemeral - perfect for testing or short-lived processes:
const identity = await createAppIdentity({ name: 'TestApp' });
// Keys lost when process exitsFile-Based Storage
Implement your own KeyStorage class (see @smartledger/crypto for interface):
import { createKeySDK } from '@smartledger/keys';
import { KeyRegistry } from '@smartledger/crypto';
import { FileKeyStorage } from './storage'; // Your implementation
const sdk = createKeySDK({
keyRegistry: new KeyRegistry(new FileKeyStorage('./keys'))
});
const identity = await createAppIdentity({
name: 'MyApp',
sdk // Use your SDK with persistence
});See /examples/file-storage/ for a complete implementation.
Database Storage
Similar pattern - implement KeyStorage for your database:
import { MongoKeyStorage } from './storage'; // Your implementation
const sdk = createKeySDK({
keyRegistry: new KeyRegistry(new MongoKeyStorage(mongoClient))
});
const identity = await createAppIdentity({ name: 'MyApp', sdk });See /examples/mongodb-storage/ for a complete implementation.
API Reference
High-Level API (Recommended)
createAppIdentity(options)
Create a signing identity:
const identity = await createAppIdentity({
name: 'MyApp', // Required: app/agent name
algorithm: 'ml-dsa-87', // Optional: 'ml-dsa-87' | 'bsv-ecdsa-secp256k1'
sdk: customSDK, // Optional: provide your own SDK with custom storage
existingKeyId: 'key-123' // Optional: use existing key
});signJson(appName, data, options?)
Convenience function for one-shot signing:
const signed = await signJson('MyApp', { message: "Hello!" });Note: Uses a global SDK instance. Keys persist across calls within the same process but are lost when the process exits.
verifyJson(envelope)
Convenience function for one-shot verification:
const result = await verifyJson(receivedEnvelope);Verifies envelopes created with signJson() in the same process.
Low-Level API (Advanced)
createSignedEnvelope(sdk, keyId, payload, options)
Full control over envelope creation:
import { createKeySDK } from '@smartledger/keys';
import { createSignedEnvelope } from '@smartledger/envelope';
const sdk = createKeySDK();
const key = await sdk.createKey('agent', { primarySignatureSuite: 'ml-dsa-87' });
const envelope = await createSignedEnvelope(sdk, key.meta.keyId, data, {
creator: 'my-agent',
contentType: 'custom-type',
metadata: { custom: 'fields' },
anchor: { chain: 'bitcoin', txId: '0x...', timestamp: '...' }
});verifySignedEnvelope(sdk, envelope, options?)
Full control over verification:
const result = await verifySignedEnvelope(sdk, envelope, {
maxAge: 86400000, // Reject if older than 24h
expectedCreator: 'alice', // Reject if not from alice
});Utility Functions
import {
extractPayload,
getEnvelopeMeta,
hasPQSignature,
hasAnchor,
createEnvelopeChain
} from '@smartledger/envelope';
// Extract payload without verification (use with caution)
const data = extractPayload(envelope);
// Get metadata
const meta = getEnvelopeMeta(envelope);
// Check capabilities
const hasPQ = hasPQSignature(envelope); // false (not implemented yet)
const hasChain = hasAnchor(envelope); // true if anchor present
// Create linked envelope
const child = await createEnvelopeChain(sdk, keyId, data, parent, options);Philosophy
Digital content should answer four questions:
- WHO - Cryptographically proven creator
- WHAT - Content hash for tamper detection
- WHEN - Timestamp (ISO 8601)
- HOW - Algorithm + public key for verification
This envelope format provides all four. The format is simple and can be verified years later.
Testing
cd packages/envelope
npm test78 tests covering:
- Envelope creation and verification
- Helper functions
- Type definitions
- Real-world scenarios (AI, blogs, microservices)
- Chain of custody
- Tampering detection
Roadmap
Current (v1.0.0)
- ✅ SignedEnvelope format
- ✅ ML-DSA-87 and ECDSA support
- ✅ Chain of custody
- ✅ Simple API
- ✅ 78 comprehensive tests
Future
- [ ] Embedded public key verification (verify without SDK)
- [ ] JWS/JWT compatibility layer
- [ ] DID document generation
- [ ] Dual-signing (ECDSA + ML-DSA)
- [ ] On-chain anchor verification
- [ ] Browser bundle
License
MIT - See LICENSE
Author
Gregory Ward (Codenlighten)
Founder: Codenlighten.org
Co-founder & CTO: SmartLedger.Technology
Related Packages
- @smartledger/keys - Key management SDK
- @smartledger/crypto - Low-level cryptography primitives
Status: 🚧 Alpha - API Stable, Features Complete, Tests Pending
The cryptographic nervous system for verifiable AI.
