@originals/sdk 1.8.2 → 1.8.3

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.
Files changed (144) hide show
  1. package/package.json +5 -6
  2. package/src/adapters/FeeOracleMock.ts +0 -9
  3. package/src/adapters/index.ts +0 -5
  4. package/src/adapters/providers/OrdHttpProvider.ts +0 -126
  5. package/src/adapters/providers/OrdMockProvider.ts +0 -101
  6. package/src/adapters/types.ts +0 -66
  7. package/src/bitcoin/BitcoinManager.ts +0 -329
  8. package/src/bitcoin/BroadcastClient.ts +0 -54
  9. package/src/bitcoin/OrdinalsClient.ts +0 -120
  10. package/src/bitcoin/PSBTBuilder.ts +0 -106
  11. package/src/bitcoin/fee-calculation.ts +0 -38
  12. package/src/bitcoin/providers/OrdNodeProvider.ts +0 -92
  13. package/src/bitcoin/providers/OrdinalsProvider.ts +0 -56
  14. package/src/bitcoin/providers/types.ts +0 -59
  15. package/src/bitcoin/transactions/commit.ts +0 -465
  16. package/src/bitcoin/transactions/index.ts +0 -13
  17. package/src/bitcoin/transfer.ts +0 -43
  18. package/src/bitcoin/utxo-selection.ts +0 -322
  19. package/src/bitcoin/utxo.ts +0 -113
  20. package/src/cel/ExternalReferenceManager.ts +0 -87
  21. package/src/cel/OriginalsCel.ts +0 -460
  22. package/src/cel/algorithms/createEventLog.ts +0 -68
  23. package/src/cel/algorithms/deactivateEventLog.ts +0 -109
  24. package/src/cel/algorithms/index.ts +0 -11
  25. package/src/cel/algorithms/updateEventLog.ts +0 -99
  26. package/src/cel/algorithms/verifyEventLog.ts +0 -306
  27. package/src/cel/algorithms/witnessEvent.ts +0 -87
  28. package/src/cel/cli/create.ts +0 -330
  29. package/src/cel/cli/index.ts +0 -383
  30. package/src/cel/cli/inspect.ts +0 -549
  31. package/src/cel/cli/migrate.ts +0 -473
  32. package/src/cel/cli/verify.ts +0 -249
  33. package/src/cel/hash.ts +0 -71
  34. package/src/cel/index.ts +0 -16
  35. package/src/cel/layers/BtcoCelManager.ts +0 -408
  36. package/src/cel/layers/PeerCelManager.ts +0 -371
  37. package/src/cel/layers/WebVHCelManager.ts +0 -361
  38. package/src/cel/layers/index.ts +0 -27
  39. package/src/cel/serialization/cbor.ts +0 -189
  40. package/src/cel/serialization/index.ts +0 -10
  41. package/src/cel/serialization/json.ts +0 -209
  42. package/src/cel/types.ts +0 -160
  43. package/src/cel/witnesses/BitcoinWitness.ts +0 -184
  44. package/src/cel/witnesses/HttpWitness.ts +0 -241
  45. package/src/cel/witnesses/WitnessService.ts +0 -51
  46. package/src/cel/witnesses/index.ts +0 -11
  47. package/src/contexts/credentials-v1.json +0 -237
  48. package/src/contexts/credentials-v2-examples.json +0 -5
  49. package/src/contexts/credentials-v2.json +0 -340
  50. package/src/contexts/credentials.json +0 -237
  51. package/src/contexts/data-integrity-v2.json +0 -81
  52. package/src/contexts/dids.json +0 -58
  53. package/src/contexts/ed255192020.json +0 -93
  54. package/src/contexts/ordinals-plus.json +0 -23
  55. package/src/contexts/originals.json +0 -22
  56. package/src/core/OriginalsSDK.ts +0 -420
  57. package/src/crypto/Multikey.ts +0 -194
  58. package/src/crypto/Signer.ts +0 -262
  59. package/src/crypto/noble-init.ts +0 -138
  60. package/src/did/BtcoDidResolver.ts +0 -231
  61. package/src/did/DIDManager.ts +0 -705
  62. package/src/did/Ed25519Verifier.ts +0 -68
  63. package/src/did/KeyManager.ts +0 -239
  64. package/src/did/WebVHManager.ts +0 -499
  65. package/src/did/createBtcoDidDocument.ts +0 -60
  66. package/src/did/providers/OrdinalsClientProviderAdapter.ts +0 -68
  67. package/src/events/EventEmitter.ts +0 -222
  68. package/src/events/index.ts +0 -19
  69. package/src/events/types.ts +0 -331
  70. package/src/examples/basic-usage.ts +0 -78
  71. package/src/examples/create-module-original.ts +0 -435
  72. package/src/examples/full-lifecycle-flow.ts +0 -514
  73. package/src/examples/run.ts +0 -60
  74. package/src/index.ts +0 -204
  75. package/src/kinds/KindRegistry.ts +0 -320
  76. package/src/kinds/index.ts +0 -74
  77. package/src/kinds/types.ts +0 -470
  78. package/src/kinds/validators/AgentValidator.ts +0 -257
  79. package/src/kinds/validators/AppValidator.ts +0 -211
  80. package/src/kinds/validators/DatasetValidator.ts +0 -242
  81. package/src/kinds/validators/DocumentValidator.ts +0 -311
  82. package/src/kinds/validators/MediaValidator.ts +0 -269
  83. package/src/kinds/validators/ModuleValidator.ts +0 -225
  84. package/src/kinds/validators/base.ts +0 -276
  85. package/src/kinds/validators/index.ts +0 -12
  86. package/src/lifecycle/BatchOperations.ts +0 -381
  87. package/src/lifecycle/LifecycleManager.ts +0 -2156
  88. package/src/lifecycle/OriginalsAsset.ts +0 -524
  89. package/src/lifecycle/ProvenanceQuery.ts +0 -280
  90. package/src/lifecycle/ResourceVersioning.ts +0 -163
  91. package/src/migration/MigrationManager.ts +0 -587
  92. package/src/migration/audit/AuditLogger.ts +0 -176
  93. package/src/migration/checkpoint/CheckpointManager.ts +0 -112
  94. package/src/migration/checkpoint/CheckpointStorage.ts +0 -101
  95. package/src/migration/index.ts +0 -33
  96. package/src/migration/operations/BaseMigration.ts +0 -126
  97. package/src/migration/operations/PeerToBtcoMigration.ts +0 -105
  98. package/src/migration/operations/PeerToWebvhMigration.ts +0 -62
  99. package/src/migration/operations/WebvhToBtcoMigration.ts +0 -105
  100. package/src/migration/rollback/RollbackManager.ts +0 -170
  101. package/src/migration/state/StateMachine.ts +0 -92
  102. package/src/migration/state/StateTracker.ts +0 -156
  103. package/src/migration/types.ts +0 -356
  104. package/src/migration/validation/BitcoinValidator.ts +0 -107
  105. package/src/migration/validation/CredentialValidator.ts +0 -62
  106. package/src/migration/validation/DIDCompatibilityValidator.ts +0 -151
  107. package/src/migration/validation/LifecycleValidator.ts +0 -64
  108. package/src/migration/validation/StorageValidator.ts +0 -79
  109. package/src/migration/validation/ValidationPipeline.ts +0 -213
  110. package/src/resources/ResourceManager.ts +0 -655
  111. package/src/resources/index.ts +0 -21
  112. package/src/resources/types.ts +0 -202
  113. package/src/storage/LocalStorageAdapter.ts +0 -64
  114. package/src/storage/MemoryStorageAdapter.ts +0 -29
  115. package/src/storage/StorageAdapter.ts +0 -25
  116. package/src/storage/index.ts +0 -3
  117. package/src/types/bitcoin.ts +0 -98
  118. package/src/types/common.ts +0 -92
  119. package/src/types/credentials.ts +0 -89
  120. package/src/types/did.ts +0 -31
  121. package/src/types/external-shims.d.ts +0 -53
  122. package/src/types/index.ts +0 -7
  123. package/src/types/network.ts +0 -178
  124. package/src/utils/EventLogger.ts +0 -298
  125. package/src/utils/Logger.ts +0 -324
  126. package/src/utils/MetricsCollector.ts +0 -358
  127. package/src/utils/bitcoin-address.ts +0 -132
  128. package/src/utils/cbor.ts +0 -31
  129. package/src/utils/encoding.ts +0 -135
  130. package/src/utils/hash.ts +0 -12
  131. package/src/utils/retry.ts +0 -46
  132. package/src/utils/satoshi-validation.ts +0 -196
  133. package/src/utils/serialization.ts +0 -102
  134. package/src/utils/telemetry.ts +0 -44
  135. package/src/utils/validation.ts +0 -123
  136. package/src/vc/CredentialManager.ts +0 -955
  137. package/src/vc/Issuer.ts +0 -105
  138. package/src/vc/Verifier.ts +0 -54
  139. package/src/vc/cryptosuites/bbs.ts +0 -253
  140. package/src/vc/cryptosuites/bbsSimple.ts +0 -21
  141. package/src/vc/cryptosuites/eddsa.ts +0 -99
  142. package/src/vc/documentLoader.ts +0 -81
  143. package/src/vc/proofs/data-integrity.ts +0 -33
  144. package/src/vc/utils/jsonld.ts +0 -18
@@ -1,955 +0,0 @@
1
- import {
2
- VerifiableCredential,
3
- VerifiablePresentation,
4
- CredentialSubject,
5
- OriginalsConfig,
6
- Proof,
7
- ExternalSigner,
8
- LayerType,
9
- AssetResource
10
- } from '../types';
11
- import { canonicalizeDocument } from '../utils/serialization';
12
- import { encodeBase64UrlMultibase, decodeBase64UrlMultibase } from '../utils/encoding';
13
- import { sha256 } from '@noble/hashes/sha2.js';
14
- import { bytesToHex } from '@noble/hashes/utils.js';
15
- import { Signer, ES256KSigner, Ed25519Signer, ES256Signer } from '../crypto/Signer';
16
- import { DIDManager } from '../did/DIDManager';
17
- import { Issuer, VerificationMethodLike } from './Issuer';
18
- import { createDocumentLoader } from './documentLoader';
19
- import { Verifier } from './Verifier';
20
-
21
- // ===== Credential Factory Types =====
22
-
23
- /**
24
- * Subject data for a ResourceCreated credential
25
- */
26
- export interface ResourceCreatedSubject {
27
- /** ID of the subject (typically the resource DID or asset DID) */
28
- id: string;
29
- /** Resource identifier */
30
- resourceId: string;
31
- /** Resource type (e.g., 'code', 'text', 'image') */
32
- resourceType: string;
33
- /** Content hash of the resource */
34
- contentHash: string;
35
- /** MIME content type */
36
- contentType: string;
37
- /** Creator DID */
38
- creator: string;
39
- /** Creation timestamp */
40
- createdAt: string;
41
- }
42
-
43
- /**
44
- * Subject data for a ResourceUpdated credential
45
- */
46
- export interface ResourceUpdatedSubject {
47
- /** ID of the subject (typically the asset DID) */
48
- id: string;
49
- /** Resource identifier */
50
- resourceId: string;
51
- /** Previous content hash */
52
- previousHash: string;
53
- /** New content hash */
54
- newHash: string;
55
- /** Previous version number */
56
- fromVersion: number;
57
- /** New version number */
58
- toVersion: number;
59
- /** Update timestamp */
60
- updatedAt: string;
61
- /** Optional description of changes */
62
- updateReason?: string;
63
- }
64
-
65
- /**
66
- * Subject data for a MigrationCompleted credential
67
- */
68
- export interface MigrationSubject {
69
- /** ID of the subject (typically the asset DID) */
70
- id: string;
71
- /** Source DID (before migration) */
72
- sourceDid: string;
73
- /** Target DID (after migration) */
74
- targetDid?: string;
75
- /** Layer migrated from */
76
- fromLayer: LayerType;
77
- /** Layer migrated to */
78
- toLayer: LayerType;
79
- /** Migration timestamp */
80
- migratedAt: string;
81
- /** Transaction ID (for Bitcoin migrations) */
82
- transactionId?: string;
83
- /** Inscription ID (for Bitcoin migrations) */
84
- inscriptionId?: string;
85
- /** Satoshi number (for Bitcoin migrations) */
86
- satoshi?: string;
87
- /** Optional reason for migration */
88
- migrationReason?: string;
89
- }
90
-
91
- /**
92
- * Subject data for an OwnershipTransferred credential
93
- */
94
- export interface OwnershipSubject {
95
- /** ID of the subject (typically the asset DID) */
96
- id: string;
97
- /** Previous owner DID or address */
98
- previousOwner: string;
99
- /** New owner DID or address */
100
- newOwner: string;
101
- /** Transfer timestamp */
102
- transferredAt: string;
103
- /** Transaction ID for the transfer */
104
- transactionId: string;
105
- /** Satoshi number of the inscription */
106
- satoshi?: string;
107
- /** Optional transfer reason or notes */
108
- transferReason?: string;
109
- }
110
-
111
- /**
112
- * Options for creating credentials with chaining
113
- */
114
- export interface CredentialChainOptions {
115
- /** Previous credential ID to chain from */
116
- previousCredentialId?: string;
117
- /** Hash of the previous credential for verification */
118
- previousCredentialHash?: string;
119
- /** Optional expiration date */
120
- expirationDate?: string;
121
- /** Optional credential status information */
122
- credentialStatus?: {
123
- id: string;
124
- type: string;
125
- };
126
- }
127
-
128
- /**
129
- * Options for BBS+ selective disclosure
130
- */
131
- export interface SelectiveDisclosureOptions {
132
- /** JSON Pointer paths to fields that must always be disclosed */
133
- mandatoryPointers: string[];
134
- /** JSON Pointer paths to fields the holder can selectively disclose */
135
- selectivePointers?: string[];
136
- }
137
-
138
- /**
139
- * Result of creating a derived proof with selective disclosure
140
- */
141
- export interface DerivedProofResult {
142
- /** The credential with derived proof */
143
- credential: VerifiableCredential;
144
- /** Fields that were disclosed */
145
- disclosedFields: string[];
146
- /** Fields that were hidden */
147
- hiddenFields: string[];
148
- }
149
-
150
- export class CredentialManager {
151
- constructor(private config: OriginalsConfig, private didManager?: DIDManager) {}
152
-
153
- createResourceCredential(
154
- type: 'ResourceCreated' | 'ResourceUpdated' | 'ResourceMigrated',
155
- subject: CredentialSubject,
156
- issuer: string
157
- ): VerifiableCredential {
158
- return {
159
- '@context': ['https://www.w3.org/2018/credentials/v1'],
160
- type: ['VerifiableCredential', type],
161
- issuer,
162
- issuanceDate: new Date().toISOString(),
163
- credentialSubject: subject
164
- };
165
- }
166
-
167
- async signCredential(
168
- credential: VerifiableCredential,
169
- privateKeyMultibase: string,
170
- verificationMethod: string
171
- ): Promise<VerifiableCredential> {
172
- if (this.didManager && typeof verificationMethod === 'string' && verificationMethod.startsWith('did:')) {
173
- try {
174
- const loader = createDocumentLoader(this.didManager);
175
- const { document } = await loader(verificationMethod);
176
- interface DocumentWithKey {
177
- publicKeyMultibase?: string;
178
- type?: string;
179
- }
180
- const docWithKey = document as DocumentWithKey;
181
- if (docWithKey && docWithKey.publicKeyMultibase) {
182
- const vm: VerificationMethodLike = {
183
- id: verificationMethod,
184
- controller: typeof credential.issuer === 'string' ? credential.issuer : (credential.issuer as { id?: string })?.id ?? '',
185
- publicKeyMultibase: docWithKey.publicKeyMultibase,
186
- secretKeyMultibase: privateKeyMultibase,
187
- type: docWithKey.type || 'Multikey'
188
- };
189
- const issuer = new Issuer(this.didManager, vm);
190
- const unsigned = { ...credential };
191
- delete (unsigned as Partial<VerifiableCredential>)['@context'];
192
- delete (unsigned as Partial<VerifiableCredential>).proof;
193
- return issuer.issueCredential(unsigned, { proofPurpose: 'assertionMethod' });
194
- }
195
- } catch {
196
- // fall through to legacy signing
197
- }
198
- }
199
-
200
- // fallback to legacy local signer
201
- const proofBase: Proof = {
202
- type: 'DataIntegrityProof',
203
- created: new Date().toISOString(),
204
- verificationMethod,
205
- proofPurpose: 'assertionMethod',
206
- proofValue: ''
207
- };
208
- const proofValue = await this.generateProofValue(credential, privateKeyMultibase, proofBase);
209
- const proof: Proof = { ...proofBase, proofValue };
210
- return { ...credential, proof };
211
- }
212
-
213
- /**
214
- * Sign a credential using an external signer (e.g., hardware wallet, Turnkey)
215
- * @param credential - The unsigned credential
216
- * @param signer - External signer implementation
217
- * @returns Signed verifiable credential
218
- */
219
- async signCredentialWithExternalSigner(
220
- credential: VerifiableCredential,
221
- signer: ExternalSigner
222
- ): Promise<VerifiableCredential> {
223
- const verificationMethodId = signer.getVerificationMethodId();
224
-
225
- // Create proof structure
226
- const proofBase = {
227
- type: 'DataIntegrityProof',
228
- cryptosuite: 'eddsa-rdfc-2022', // Or derive from signer type
229
- created: new Date().toISOString(),
230
- verificationMethod: verificationMethodId,
231
- proofPurpose: 'assertionMethod'
232
- };
233
-
234
- // Prepare unsigned credential
235
- const unsignedCredential: Record<string, unknown> = { ...credential };
236
- delete unsignedCredential.proof;
237
-
238
- // Use external signer to sign
239
- const { proofValue } = await signer.sign({
240
- document: unsignedCredential,
241
- proof: proofBase
242
- });
243
-
244
- // Return signed credential
245
- return {
246
- ...credential,
247
- proof: {
248
- ...proofBase,
249
- proofValue
250
- }
251
- };
252
- }
253
-
254
- async verifyCredential(credential: VerifiableCredential): Promise<boolean> {
255
- if (this.didManager) {
256
- interface ProofWithCryptosuite {
257
- cryptosuite?: string;
258
- }
259
- const proofValue = credential.proof;
260
- const proofWithSuite = proofValue as ProofWithCryptosuite | ProofWithCryptosuite[] | undefined;
261
- if (proofWithSuite) {
262
- const hasCryptosuite = Array.isArray(proofWithSuite)
263
- ? proofWithSuite[0]?.cryptosuite
264
- : proofWithSuite.cryptosuite;
265
- if (hasCryptosuite) {
266
- const verifier = new Verifier(this.didManager);
267
- const res = await verifier.verifyCredential(credential);
268
- return res.verified;
269
- }
270
- }
271
- }
272
-
273
- const proof = credential.proof as Proof | undefined;
274
- if (!proof) {
275
- return false;
276
- }
277
-
278
- const { proofValue, verificationMethod } = proof;
279
- if (!proofValue || !verificationMethod) return false;
280
-
281
- const signature = this.decodeMultibase(proofValue);
282
- if (!signature) return false;
283
-
284
- const proofSansValue = { ...proof } as Record<string, unknown>;
285
- delete proofSansValue.proofValue;
286
- const proofInput: Record<string, unknown> = { ...proofSansValue };
287
- const credentialContext = credential['@context'];
288
- if (credentialContext && !proofInput['@context']) {
289
- proofInput['@context'] = credentialContext;
290
- }
291
- const unsignedCredential: Record<string, unknown> = { ...credential };
292
- delete unsignedCredential.proof;
293
-
294
- const c14nProof = await canonicalizeDocument(proofInput);
295
- const c14nCred = await canonicalizeDocument(unsignedCredential);
296
- const hProof = Buffer.from(sha256(Buffer.from(c14nProof, 'utf8')));
297
- const hCred = Buffer.from(sha256(Buffer.from(c14nCred, 'utf8')));
298
- const digest = Buffer.concat([hProof, hCred]);
299
- const signer = this.getSigner();
300
- try {
301
- const proofWithKey = proof as Proof & { publicKeyMultibase?: string };
302
- const resolvedKey = proofWithKey.publicKeyMultibase
303
- || await this.resolveVerificationMethodMultibase(verificationMethod);
304
- if (!resolvedKey) {
305
- return false;
306
- }
307
- return await signer.verify(Buffer.from(digest), Buffer.from(signature), resolvedKey);
308
- } catch {
309
- return false;
310
- }
311
- }
312
-
313
- createPresentation(
314
- credentials: VerifiableCredential[],
315
- holder: string
316
- ): VerifiablePresentation {
317
- return {
318
- '@context': ['https://www.w3.org/2018/credentials/v1'],
319
- type: ['VerifiablePresentation'],
320
- holder,
321
- verifiableCredential: credentials
322
- } as VerifiablePresentation;
323
- }
324
-
325
- private async generateProofValue(
326
- credential: VerifiableCredential,
327
- privateKeyMultibase: string,
328
- proofBase: Proof
329
- ): Promise<string> {
330
- // Construct canonical digest including provided proof sans proofValue
331
- const proofSansValue = { ...proofBase } as Record<string, unknown>;
332
- delete proofSansValue.proofValue;
333
- const proofInput: Record<string, unknown> = { ...proofSansValue };
334
- const credentialContext = credential['@context'];
335
- if (credentialContext && !proofInput['@context']) {
336
- proofInput['@context'] = credentialContext;
337
- }
338
- const unsignedCredential: Record<string, unknown> = { ...credential };
339
- delete unsignedCredential.proof;
340
-
341
- const c14nProof = await canonicalizeDocument(proofInput);
342
- const c14nCred = await canonicalizeDocument(unsignedCredential);
343
- const hProof = Buffer.from(sha256(Buffer.from(c14nProof, 'utf8')));
344
- const hCred = Buffer.from(sha256(Buffer.from(c14nCred, 'utf8')));
345
- const digest = Buffer.concat([hProof, hCred]);
346
- const signer = this.getSigner();
347
- const sig = await signer.sign(Buffer.from(digest), privateKeyMultibase);
348
- return encodeBase64UrlMultibase(sig);
349
- }
350
-
351
- private getSigner(): Signer {
352
- switch (this.config.defaultKeyType) {
353
- case 'ES256K':
354
- return new ES256KSigner();
355
- case 'Ed25519':
356
- return new Ed25519Signer();
357
- case 'ES256':
358
- return new ES256Signer();
359
- default:
360
- return new ES256KSigner();
361
- }
362
- }
363
-
364
- private async resolveVerificationMethodMultibase(
365
- verificationMethod: string
366
- ): Promise<string | null> {
367
- if (typeof verificationMethod === 'string' && verificationMethod.startsWith('z')) {
368
- return verificationMethod;
369
- }
370
-
371
- if (!this.didManager || typeof verificationMethod !== 'string' || !verificationMethod.startsWith('did:')) {
372
- return null;
373
- }
374
-
375
- const loader = createDocumentLoader(this.didManager);
376
- try {
377
- const { document } = await loader(verificationMethod);
378
- interface DocWithKey {
379
- publicKeyMultibase?: unknown;
380
- }
381
- const docWithKey = document as DocWithKey;
382
- if (docWithKey && typeof docWithKey.publicKeyMultibase === 'string') {
383
- return docWithKey.publicKeyMultibase;
384
- }
385
- } catch (err) {
386
- // Document loader failed; will try alternative resolution method
387
- if (this.config.enableLogging) {
388
- console.warn('Failed to load verification method via document loader:', err);
389
- }
390
- }
391
-
392
- try {
393
- const did = verificationMethod.split('#')[0];
394
- if (!did) {
395
- return null;
396
- }
397
- const didDoc = await this.didManager.resolveDID(did);
398
- interface DIDDocWithVMs {
399
- verificationMethod?: Array<{ id?: string; publicKeyMultibase?: unknown }>;
400
- }
401
- const docWithVMs = didDoc as DIDDocWithVMs;
402
- const vms = docWithVMs?.verificationMethod;
403
- if (Array.isArray(vms)) {
404
- const vm = vms.find((m) => m?.id === verificationMethod);
405
- if (vm && typeof vm.publicKeyMultibase === 'string') {
406
- return vm.publicKeyMultibase;
407
- }
408
- }
409
- } catch (err) {
410
- // Failed to resolve DID document
411
- if (this.config.enableLogging) {
412
- console.warn('Failed to resolve DID for verification method:', err);
413
- }
414
- }
415
-
416
- return null;
417
- }
418
-
419
- private decodeMultibase(s: string): Uint8Array | null {
420
- try {
421
- return decodeBase64UrlMultibase(s);
422
- } catch {
423
- return null;
424
- }
425
- }
426
-
427
- // ===== Credential Factory Methods =====
428
-
429
- /**
430
- * Issue a ResourceCreated credential for a newly created resource
431
- *
432
- * @param resource - The created resource
433
- * @param assetDid - The DID of the asset containing the resource
434
- * @param creatorDid - The DID of the creator
435
- * @param chainOptions - Optional chaining options for linking to previous credentials
436
- * @returns Unsigned verifiable credential
437
- *
438
- * @example
439
- * ```typescript
440
- * const credential = await credentialManager.issueResourceCredential(
441
- * resource,
442
- * 'did:peer:abc...',
443
- * 'did:peer:creator...'
444
- * );
445
- * // Sign the credential with your key
446
- * const signed = await credentialManager.signCredential(credential, privateKey, vmId);
447
- * ```
448
- */
449
- issueResourceCredential(
450
- resource: AssetResource,
451
- assetDid: string,
452
- creatorDid: string,
453
- chainOptions?: CredentialChainOptions
454
- ): VerifiableCredential {
455
- const subject: ResourceCreatedSubject = {
456
- id: assetDid,
457
- resourceId: resource.id,
458
- resourceType: resource.type,
459
- contentHash: resource.hash,
460
- contentType: resource.contentType,
461
- creator: creatorDid,
462
- createdAt: resource.createdAt || new Date().toISOString()
463
- };
464
-
465
- const credential = this.createCredentialWithChain(
466
- 'ResourceCreated',
467
- subject,
468
- creatorDid,
469
- chainOptions
470
- );
471
-
472
- return credential;
473
- }
474
-
475
- /**
476
- * Issue a ResourceUpdated credential for a resource version update
477
- *
478
- * @param resourceId - The logical resource ID
479
- * @param assetDid - The DID of the asset
480
- * @param previousHash - Hash of the previous version
481
- * @param newHash - Hash of the new version
482
- * @param fromVersion - Previous version number
483
- * @param toVersion - New version number
484
- * @param updaterDid - DID of the entity performing the update
485
- * @param updateReason - Optional reason for the update
486
- * @param chainOptions - Optional chaining options
487
- * @returns Unsigned verifiable credential
488
- *
489
- * @example
490
- * ```typescript
491
- * const credential = await credentialManager.issueResourceUpdateCredential(
492
- * 'main.js',
493
- * 'did:webvh:example.com:asset',
494
- * 'abc123...',
495
- * 'def456...',
496
- * 1,
497
- * 2,
498
- * 'did:webvh:example.com:user',
499
- * 'Bug fix'
500
- * );
501
- * ```
502
- */
503
- issueResourceUpdateCredential(
504
- resourceId: string,
505
- assetDid: string,
506
- previousHash: string,
507
- newHash: string,
508
- fromVersion: number,
509
- toVersion: number,
510
- updaterDid: string,
511
- updateReason?: string,
512
- chainOptions?: CredentialChainOptions
513
- ): VerifiableCredential {
514
- const subject: ResourceUpdatedSubject = {
515
- id: assetDid,
516
- resourceId,
517
- previousHash,
518
- newHash,
519
- fromVersion,
520
- toVersion,
521
- updatedAt: new Date().toISOString(),
522
- ...(updateReason && { updateReason })
523
- };
524
-
525
- const credential = this.createCredentialWithChain(
526
- 'ResourceUpdated',
527
- subject,
528
- updaterDid,
529
- chainOptions
530
- );
531
-
532
- return credential;
533
- }
534
-
535
- /**
536
- * Issue a MigrationCompleted credential for layer migrations
537
- *
538
- * Records the migration of an asset between Originals layers (peer -> webvh -> btco).
539
- *
540
- * @param sourceDid - The source DID (before migration)
541
- * @param targetDid - The target DID (after migration, if different)
542
- * @param fromLayer - The source layer
543
- * @param toLayer - The target layer
544
- * @param issuerDid - The DID issuing this credential
545
- * @param details - Optional migration details (transactionId, inscriptionId, satoshi)
546
- * @param chainOptions - Optional chaining options
547
- * @returns Unsigned verifiable credential
548
- *
549
- * @example
550
- * ```typescript
551
- * const credential = await credentialManager.issueMigrationCredential(
552
- * 'did:peer:abc...',
553
- * 'did:webvh:example.com:asset',
554
- * 'did:peer',
555
- * 'did:webvh',
556
- * 'did:webvh:example.com:publisher'
557
- * );
558
- * ```
559
- */
560
- issueMigrationCredential(
561
- sourceDid: string,
562
- targetDid: string | undefined,
563
- fromLayer: LayerType,
564
- toLayer: LayerType,
565
- issuerDid: string,
566
- details?: {
567
- transactionId?: string;
568
- inscriptionId?: string;
569
- satoshi?: string;
570
- migrationReason?: string;
571
- },
572
- chainOptions?: CredentialChainOptions
573
- ): VerifiableCredential {
574
- const subject: MigrationSubject = {
575
- id: targetDid || sourceDid,
576
- sourceDid,
577
- ...(targetDid && { targetDid }),
578
- fromLayer,
579
- toLayer,
580
- migratedAt: new Date().toISOString(),
581
- ...(details?.transactionId && { transactionId: details.transactionId }),
582
- ...(details?.inscriptionId && { inscriptionId: details.inscriptionId }),
583
- ...(details?.satoshi && { satoshi: details.satoshi }),
584
- ...(details?.migrationReason && { migrationReason: details.migrationReason })
585
- };
586
-
587
- const credential = this.createCredentialWithChain(
588
- 'MigrationCompleted',
589
- subject,
590
- issuerDid,
591
- chainOptions
592
- );
593
-
594
- return credential;
595
- }
596
-
597
- /**
598
- * Issue an OwnershipTransferred credential for Bitcoin-anchored asset transfers
599
- *
600
- * Records the transfer of ownership of a did:btco asset to a new owner.
601
- *
602
- * @param assetDid - The DID of the asset being transferred
603
- * @param previousOwner - The previous owner (DID or Bitcoin address)
604
- * @param newOwner - The new owner (Bitcoin address)
605
- * @param transactionId - The Bitcoin transaction ID
606
- * @param issuerDid - The DID issuing this credential
607
- * @param details - Optional additional details
608
- * @param chainOptions - Optional chaining options
609
- * @returns Unsigned verifiable credential
610
- *
611
- * @example
612
- * ```typescript
613
- * const credential = await credentialManager.issueOwnershipCredential(
614
- * 'did:btco:12345',
615
- * 'bc1q...oldowner',
616
- * 'bc1q...newowner',
617
- * 'abc123...txid',
618
- * 'did:btco:12345'
619
- * );
620
- * ```
621
- */
622
- issueOwnershipCredential(
623
- assetDid: string,
624
- previousOwner: string,
625
- newOwner: string,
626
- transactionId: string,
627
- issuerDid: string,
628
- details?: {
629
- satoshi?: string;
630
- transferReason?: string;
631
- },
632
- chainOptions?: CredentialChainOptions
633
- ): VerifiableCredential {
634
- const subject: OwnershipSubject = {
635
- id: assetDid,
636
- previousOwner,
637
- newOwner,
638
- transferredAt: new Date().toISOString(),
639
- transactionId,
640
- ...(details?.satoshi && { satoshi: details.satoshi }),
641
- ...(details?.transferReason && { transferReason: details.transferReason })
642
- };
643
-
644
- const credential = this.createCredentialWithChain(
645
- 'OwnershipTransferred',
646
- subject,
647
- issuerDid,
648
- chainOptions
649
- );
650
-
651
- return credential;
652
- }
653
-
654
- /**
655
- * Create a credential with optional chaining to a previous credential
656
- *
657
- * Credential chaining creates a verifiable provenance chain by linking
658
- * credentials together through their IDs and hashes.
659
- *
660
- * @param type - The credential type
661
- * @param subject - The credential subject
662
- * @param issuer - The issuer DID
663
- * @param chainOptions - Optional chaining options
664
- * @returns Unsigned verifiable credential with chain metadata
665
- */
666
- private createCredentialWithChain(
667
- type: string,
668
- subject: CredentialSubject,
669
- issuer: string,
670
- chainOptions?: CredentialChainOptions
671
- ): VerifiableCredential {
672
- const credential: VerifiableCredential = {
673
- '@context': [
674
- 'https://www.w3.org/2018/credentials/v1',
675
- 'https://w3id.org/security/data-integrity/v2'
676
- ],
677
- type: ['VerifiableCredential', type],
678
- id: this.generateCredentialId(),
679
- issuer,
680
- issuanceDate: new Date().toISOString(),
681
- credentialSubject: subject
682
- };
683
-
684
- // Add expiration if specified
685
- if (chainOptions?.expirationDate) {
686
- credential.expirationDate = chainOptions.expirationDate;
687
- }
688
-
689
- // Add credential status if specified
690
- if (chainOptions?.credentialStatus) {
691
- credential.credentialStatus = chainOptions.credentialStatus;
692
- }
693
-
694
- // Add chaining metadata if provided
695
- if (chainOptions?.previousCredentialId || chainOptions?.previousCredentialHash) {
696
- interface SubjectWithPrevious {
697
- previousCredential?: {
698
- id?: string;
699
- hash?: string;
700
- };
701
- }
702
- const subjectWithPrev = credential.credentialSubject as CredentialSubject & SubjectWithPrevious;
703
- subjectWithPrev.previousCredential = {
704
- ...(chainOptions.previousCredentialId && { id: chainOptions.previousCredentialId }),
705
- ...(chainOptions.previousCredentialHash && { hash: chainOptions.previousCredentialHash })
706
- };
707
- }
708
-
709
- return credential;
710
- }
711
-
712
- /**
713
- * Generate a unique credential ID
714
- */
715
- private generateCredentialId(): string {
716
- const timestamp = Date.now();
717
- const randomBytes = new Uint8Array(16);
718
- if (typeof globalThis.crypto?.getRandomValues === 'function') {
719
- globalThis.crypto.getRandomValues(randomBytes);
720
- } else {
721
- // Fallback for environments without crypto.getRandomValues
722
- for (let i = 0; i < 16; i++) {
723
- randomBytes[i] = Math.floor(Math.random() * 256);
724
- }
725
- }
726
- const randomHex = bytesToHex(randomBytes);
727
- return `urn:uuid:${timestamp}-${randomHex.substring(0, 8)}-${randomHex.substring(8, 16)}`;
728
- }
729
-
730
- /**
731
- * Compute the hash of a credential for chaining purposes
732
- *
733
- * @param credential - The credential to hash
734
- * @returns SHA-256 hash of the canonicalized credential
735
- */
736
- async computeCredentialHash(credential: VerifiableCredential): Promise<string> {
737
- const canonicalized = await canonicalizeDocument(credential as unknown as Record<string, unknown>);
738
- const hash = sha256(Buffer.from(canonicalized, 'utf8'));
739
- return bytesToHex(hash);
740
- }
741
-
742
- /**
743
- * Verify a credential chain by checking all previous credential links
744
- *
745
- * @param credentials - Array of credentials in chain order (oldest first)
746
- * @returns Verification result with chain integrity status
747
- */
748
- async verifyCredentialChain(credentials: VerifiableCredential[]): Promise<{
749
- valid: boolean;
750
- errors: string[];
751
- chainLength: number;
752
- }> {
753
- const errors: string[] = [];
754
-
755
- if (credentials.length === 0) {
756
- return { valid: true, errors: [], chainLength: 0 };
757
- }
758
-
759
- // Verify each credential individually
760
- for (let i = 0; i < credentials.length; i++) {
761
- const isValid = await this.verifyCredential(credentials[i]);
762
- if (!isValid) {
763
- errors.push(`Credential at index ${i} failed verification`);
764
- }
765
- }
766
-
767
- // Verify chain links
768
- for (let i = 1; i < credentials.length; i++) {
769
- const current = credentials[i];
770
- const previous = credentials[i - 1];
771
-
772
- interface SubjectWithPrevious {
773
- previousCredential?: {
774
- id?: string;
775
- hash?: string;
776
- };
777
- }
778
- const currentSubject = current.credentialSubject as CredentialSubject & SubjectWithPrevious;
779
- const previousCredRef = currentSubject?.previousCredential;
780
-
781
- if (previousCredRef) {
782
- // Verify ID link
783
- if (previousCredRef.id && previousCredRef.id !== previous.id) {
784
- errors.push(`Chain broken at index ${i}: previousCredential.id doesn't match`);
785
- }
786
-
787
- // Verify hash link
788
- if (previousCredRef.hash) {
789
- const expectedHash = await this.computeCredentialHash(previous);
790
- if (previousCredRef.hash !== expectedHash) {
791
- errors.push(`Chain broken at index ${i}: previousCredential.hash doesn't match`);
792
- }
793
- }
794
- }
795
- }
796
-
797
- return {
798
- valid: errors.length === 0,
799
- errors,
800
- chainLength: credentials.length
801
- };
802
- }
803
-
804
- // ===== BBS+ Selective Disclosure =====
805
-
806
- /**
807
- * Prepare a credential for BBS+ selective disclosure
808
- *
809
- * This creates a base proof that can later be derived into a proof
810
- * that selectively discloses only certain fields.
811
- *
812
- * Note: This requires BBS+ keys and is primarily used for privacy-preserving
813
- * credential presentations.
814
- *
815
- * @param credential - The credential to prepare
816
- * @param options - Selective disclosure options
817
- * @returns The credential with BBS+ base proof metadata
818
- */
819
- async prepareSelectiveDisclosure(
820
- credential: VerifiableCredential,
821
- options: SelectiveDisclosureOptions
822
- ): Promise<{
823
- credential: VerifiableCredential;
824
- mandatoryPointers: string[];
825
- selectivePointers: string[];
826
- }> {
827
- // Validate mandatory pointers
828
- if (!options.mandatoryPointers || options.mandatoryPointers.length === 0) {
829
- throw new Error('At least one mandatory pointer is required for selective disclosure');
830
- }
831
-
832
- // Validate pointer format (JSON Pointers must start with /)
833
- for (const pointer of options.mandatoryPointers) {
834
- if (!pointer.startsWith('/')) {
835
- throw new Error(`Invalid JSON Pointer: ${pointer} (must start with /)`);
836
- }
837
- }
838
-
839
- const selectivePointers = options.selectivePointers || [];
840
- for (const pointer of selectivePointers) {
841
- if (!pointer.startsWith('/')) {
842
- throw new Error(`Invalid JSON Pointer: ${pointer} (must start with /)`);
843
- }
844
- }
845
-
846
- // Add selective disclosure metadata to credential
847
- const enhancedCredential = {
848
- ...credential,
849
- // Store pointers in credential for later derivation
850
- // In a full implementation, this would involve creating a BBS+ base proof
851
- };
852
-
853
- return await Promise.resolve({
854
- credential: enhancedCredential,
855
- mandatoryPointers: options.mandatoryPointers,
856
- selectivePointers
857
- });
858
- }
859
-
860
- /**
861
- * Create a derived proof with selective disclosure
862
- *
863
- * Given a credential with a BBS+ base proof, creates a derived proof
864
- * that only reveals the specified fields.
865
- *
866
- * @param credential - The credential with BBS+ base proof
867
- * @param fieldsToDisclose - JSON Pointer paths to disclose
868
- * @param presentationHeader - Optional presentation-specific data
869
- * @returns The credential with derived proof
870
- */
871
- async deriveSelectiveProof(
872
- credential: VerifiableCredential,
873
- fieldsToDisclose: string[],
874
- _presentationHeader?: Uint8Array
875
- ): Promise<DerivedProofResult> {
876
- // Validate that all disclosed fields are valid JSON pointers
877
- for (const field of fieldsToDisclose) {
878
- if (!field.startsWith('/')) {
879
- throw new Error(`Invalid JSON Pointer for disclosure: ${field}`);
880
- }
881
- }
882
-
883
- // Determine which fields will be hidden
884
- const allFields = this.extractFieldPaths(credential as unknown as Record<string, unknown>);
885
- const disclosedSet = new Set(fieldsToDisclose);
886
- const hiddenFields = allFields.filter(f => !disclosedSet.has(f));
887
-
888
- // In a full implementation, this would:
889
- // 1. Parse the base proof
890
- // 2. Create selective indexes from fieldsToDisclose
891
- // 3. Generate the derived BBS+ proof
892
- // For now, we return a structure showing what would be disclosed
893
-
894
- return await Promise.resolve({
895
- credential: {
896
- ...credential,
897
- // A real implementation would have a derived proof here
898
- },
899
- disclosedFields: fieldsToDisclose,
900
- hiddenFields
901
- });
902
- }
903
-
904
- /**
905
- * Extract all field paths from a credential as JSON Pointers
906
- */
907
- private extractFieldPaths(obj: Record<string, unknown>, prefix = ''): string[] {
908
- const paths: string[] = [];
909
-
910
- if (typeof obj !== 'object' || obj === null) {
911
- return paths;
912
- }
913
-
914
- for (const [key, value] of Object.entries(obj)) {
915
- const path = `${prefix}/${key}`;
916
- paths.push(path);
917
-
918
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
919
- paths.push(...this.extractFieldPaths(value as Record<string, unknown>, path));
920
- }
921
- }
922
-
923
- return paths;
924
- }
925
-
926
- /**
927
- * Get field value from credential using JSON Pointer
928
- *
929
- * @param credential - The credential to read from
930
- * @param pointer - JSON Pointer path (e.g., /credentialSubject/name)
931
- * @returns The value at the pointer path, or undefined if not found
932
- */
933
- getFieldByPointer(credential: VerifiableCredential, pointer: string): unknown {
934
- if (!pointer.startsWith('/')) {
935
- throw new Error('JSON Pointer must start with /');
936
- }
937
-
938
- const parts = pointer.slice(1).split('/');
939
- let current: unknown = credential;
940
-
941
- for (const part of parts) {
942
- if (current === null || current === undefined) {
943
- return undefined;
944
- }
945
- // Handle escaped characters in JSON Pointer
946
- const unescaped = part.replace(/~1/g, '/').replace(/~0/g, '~');
947
- const currentObj = current as Record<string, unknown>;
948
- current = currentObj[unescaped];
949
- }
950
-
951
- return current;
952
- }
953
- }
954
-
955
-