@smartledger/bsv 3.2.1 → 3.3.2

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 (70) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/README.md +289 -55
  3. package/architecture_demo.js +247 -0
  4. package/bsv-covenant.min.js +10 -0
  5. package/bsv-gdaf.min.js +37 -0
  6. package/bsv-ltp.min.js +37 -0
  7. package/bsv-script-helper.min.js +10 -0
  8. package/bsv-security.min.js +31 -0
  9. package/bsv-shamir.min.js +12 -0
  10. package/bsv-smartcontract.min.js +37 -0
  11. package/bsv.bundle.js +9 -9
  12. package/bsv.min.js +3 -3
  13. package/build/bsv-covenant.min.js +10 -0
  14. package/build/bsv-script-helper.min.js +10 -0
  15. package/build/bsv-security.min.js +31 -0
  16. package/build/bsv-smartcontract.min.js +39 -0
  17. package/build/bsv.bundle.js +39 -0
  18. package/build/bsv.min.js +39 -0
  19. package/build/webpack.bundle.config.js +22 -0
  20. package/build/webpack.config.js +18 -0
  21. package/build/webpack.covenant.config.js +27 -0
  22. package/build/webpack.gdaf.config.js +54 -0
  23. package/build/webpack.ltp.config.js +17 -0
  24. package/build/webpack.script-helper.config.js +27 -0
  25. package/build/webpack.security.config.js +23 -0
  26. package/build/webpack.smartcontract.config.js +25 -0
  27. package/build/webpack.subproject.config.js +6 -0
  28. package/bundle-entry.js +341 -0
  29. package/complete_ltp_demo.js +511 -0
  30. package/covenant-entry.js +44 -0
  31. package/docs/pushtx-key-insights.md +106 -0
  32. package/gdaf-entry.js +54 -0
  33. package/index.js +272 -5
  34. package/lib/crypto/shamir.js +360 -0
  35. package/lib/gdaf/attestation-signer.js +461 -0
  36. package/lib/gdaf/attestation-verifier.js +600 -0
  37. package/lib/gdaf/did-resolver.js +382 -0
  38. package/lib/gdaf/index.js +471 -0
  39. package/lib/gdaf/schema-validator.js +682 -0
  40. package/lib/gdaf/smartledger-anchor.js +486 -0
  41. package/lib/gdaf/zk-prover.js +507 -0
  42. package/lib/ltp/anchor.js +438 -0
  43. package/lib/ltp/claim.js +1026 -0
  44. package/lib/ltp/index.js +470 -0
  45. package/lib/ltp/obligation.js +945 -0
  46. package/lib/ltp/proof.js +828 -0
  47. package/lib/ltp/registry.js +702 -0
  48. package/lib/ltp/right.js +765 -0
  49. package/lib/smart_contract/API_REFERENCE.md +1 -1
  50. package/lib/smart_contract/EXAMPLES.md +2 -2
  51. package/lib/smart_contract/QUICK_START.md +2 -2
  52. package/lib/smart_contract/README.md +1 -1
  53. package/lib/smart_contract/index.js +4 -0
  54. package/ltp-entry.js +92 -0
  55. package/package.json +91 -20
  56. package/script-helper-entry.js +49 -0
  57. package/security-entry.js +70 -0
  58. package/shamir-entry.js +173 -0
  59. package/shamir_demo.js +121 -0
  60. package/simple_demo.js +204 -0
  61. package/smartcontract-entry.js +133 -0
  62. package/test_shamir.js +221 -0
  63. package/test_standalone_shamir.html +83 -0
  64. package/tests/bundle-completeness-test.html +131 -0
  65. package/tests/bundle-demo.html +476 -0
  66. package/tests/smartcontract-test.html +239 -0
  67. package/tests/standalone-modules-test.html +260 -0
  68. package/tests/test.html +612 -0
  69. package/tests/unpkg-demo.html +194 -0
  70. package/docs/nchain.md +0 -958
@@ -0,0 +1,765 @@
1
+ 'use strict'
2
+
3
+ var bsv = require('../../')
4
+ var Hash = bsv.crypto.Hash
5
+ var ECDSA = bsv.crypto.ECDSA
6
+ var PrivateKey = bsv.PrivateKey
7
+ var $ = bsv.util.preconditions
8
+ var _ = require('../util/_')
9
+
10
+ /**
11
+ * Legal Token Protocol - Right Creation Primitives
12
+ *
13
+ * Provides primitives for legal rights token creation, validation, and transfer
14
+ * without direct blockchain publishing. External systems handle token storage
15
+ * and blockchain anchoring operations.
16
+ */
17
+
18
+ /**
19
+ * Right Token Types
20
+ */
21
+ var RightTypes = {
22
+ PROPERTY_TITLE: 'PropertyTitle',
23
+ VEHICLE_TITLE: 'VehicleTitle',
24
+ INTELLECTUAL_PROPERTY: 'IntellectualProperty',
25
+ MUSIC_LICENSE: 'MusicLicense',
26
+ SOFTWARE_LICENSE: 'SoftwareLicense',
27
+ FINANCIAL_INSTRUMENT: 'FinancialInstrument',
28
+ PROMISSORY_NOTE: 'PromissoryNote',
29
+ BOND: 'Bond',
30
+ EQUITY_SHARE: 'EquityShare',
31
+ PROFESSIONAL_LICENSE: 'ProfessionalLicense',
32
+ REGULATORY_PERMIT: 'RegulatoryPermit',
33
+ ACCESS_RIGHT: 'AccessRight',
34
+ VOTING_RIGHT: 'VotingRight',
35
+ ROYALTY_RIGHT: 'RoyaltyRight',
36
+ USAGE_RIGHT: 'UsageRight'
37
+ }
38
+
39
+ /**
40
+ * Legal Right Token
41
+ */
42
+ var RightToken = {
43
+
44
+ /**
45
+ * Prepare legal right token for external processing
46
+ * @param {String} type - Right type (from RightTypes)
47
+ * @param {String} issuerDID - Issuer DID
48
+ * @param {String} subjectDID - Subject DID
49
+ * @param {Object} claim - Legal claim object
50
+ * @param {PrivateKey} issuerPrivateKey - Issuer's private key
51
+ * @param {Object} options - Additional options
52
+ * @returns {Object} Prepared legal right token data
53
+ */
54
+ prepareRightToken: function(type, issuerDID, subjectDID, claim, issuerPrivateKey, options) {
55
+ options = options || {}
56
+
57
+ $.checkArgument(typeof type === 'string', 'Right type must be string')
58
+ $.checkArgument(typeof issuerDID === 'string', 'Issuer DID must be string')
59
+ $.checkArgument(typeof subjectDID === 'string', 'Subject DID must be string')
60
+ $.checkArgument(claim && typeof claim === 'object', 'Claim must be object')
61
+ $.checkArgument(issuerPrivateKey instanceof PrivateKey, 'Invalid issuer private key')
62
+
63
+ // Validate right type
64
+ var validTypes = Object.values(RightTypes)
65
+ $.checkArgument(validTypes.includes(type), 'Invalid right type: ' + type)
66
+
67
+ try {
68
+ var rightToken = {
69
+ '@context': [
70
+ 'https://www.w3.org/2018/credentials/v1',
71
+ 'https://smartledger.technology/contexts/ltp/v1'
72
+ ],
73
+ id: 'urn:uuid:' + this._generateUUID(),
74
+ type: ['VerifiableCredential', 'LegalRightToken', type],
75
+ issuer: issuerDID,
76
+ issuanceDate: new Date().toISOString(),
77
+ credentialSubject: {
78
+ id: subjectDID,
79
+ rightType: type,
80
+ claim: claim,
81
+ jurisdiction: options.jurisdiction || 'US',
82
+ purpose: options.purpose || 'legal_right',
83
+ validFrom: options.validFrom || new Date().toISOString(),
84
+ validUntil: options.validUntil || null,
85
+ transferable: options.transferable !== false,
86
+ revocable: options.revocable !== false
87
+ }
88
+ }
89
+
90
+ // Add metadata
91
+ if (options.metadata) {
92
+ rightToken.credentialSubject.metadata = options.metadata
93
+ }
94
+
95
+ // Sign the token
96
+ var signedToken = this._signToken(rightToken, issuerPrivateKey)
97
+
98
+ return {
99
+ success: true,
100
+ rightToken: signedToken,
101
+ tokenHash: signedToken.tokenHash,
102
+ metadata: {
103
+ type: type,
104
+ issuer: issuerDID,
105
+ subject: subjectDID,
106
+ transferable: rightToken.credentialSubject.transferable,
107
+ revocable: rightToken.credentialSubject.revocable,
108
+ jurisdiction: rightToken.credentialSubject.jurisdiction
109
+ },
110
+ externalOperations: {
111
+ storeToken: {
112
+ endpoint: 'POST /rights/tokens',
113
+ data: {
114
+ token: signedToken,
115
+ metadata: {
116
+ type: type,
117
+ issuer: issuerDID,
118
+ subject: subjectDID,
119
+ transferable: rightToken.credentialSubject.transferable,
120
+ revocable: rightToken.credentialSubject.revocable,
121
+ jurisdiction: rightToken.credentialSubject.jurisdiction
122
+ }
123
+ }
124
+ },
125
+ indexToken: {
126
+ endpoint: 'POST /rights/index',
127
+ data: {
128
+ tokenId: signedToken.id,
129
+ tokenHash: signedToken.tokenHash,
130
+ type: type,
131
+ issuer: issuerDID,
132
+ subject: subjectDID,
133
+ issuedAt: signedToken.issuanceDate
134
+ }
135
+ },
136
+ notifyParties: {
137
+ endpoint: 'POST /notifications/right-issued',
138
+ data: {
139
+ tokenId: signedToken.id,
140
+ issuer: issuerDID,
141
+ subject: subjectDID,
142
+ rightType: type
143
+ }
144
+ }
145
+ }
146
+ }
147
+
148
+ } catch (error) {
149
+ return {
150
+ success: false,
151
+ error: error.message
152
+ }
153
+ }
154
+ },
155
+
156
+ /**
157
+ * Prepare right token verification for external processing
158
+ * @param {Object} token - Right token to verify
159
+ * @param {Object} options - Verification options
160
+ * @returns {Object} Prepared verification data
161
+ */
162
+ prepareRightTokenVerification: function(token, options) {
163
+ options = options || {}
164
+
165
+ try {
166
+ var errors = []
167
+ var warnings = []
168
+
169
+ // Basic structure validation
170
+ this._validateTokenStructure(token, errors)
171
+
172
+ // Signature verification
173
+ this._verifyTokenSignature(token, errors)
174
+
175
+ // Temporal validation
176
+ this._validateTokenTemporal(token, errors, warnings)
177
+
178
+ // Type validation
179
+ this._validateRightType(token, errors)
180
+
181
+ // Jurisdiction validation
182
+ if (options.requireJurisdiction) {
183
+ this._validateJurisdiction(token, options.allowedJurisdictions, errors)
184
+ }
185
+
186
+ var verification = {
187
+ valid: errors.length === 0,
188
+ errors: errors,
189
+ warnings: warnings,
190
+ issuerDID: token.issuer,
191
+ subjectDID: token.credentialSubject ? token.credentialSubject.id : null,
192
+ rightType: token.credentialSubject ? token.credentialSubject.rightType : null,
193
+ transferable: token.credentialSubject ? token.credentialSubject.transferable : null,
194
+ revocable: token.credentialSubject ? token.credentialSubject.revocable : null,
195
+ verifiedAt: new Date().toISOString()
196
+ }
197
+
198
+ return {
199
+ success: true,
200
+ verification: verification,
201
+ externalOperations: {
202
+ recordVerification: {
203
+ endpoint: 'POST /rights/verification-record',
204
+ data: {
205
+ tokenId: token.id,
206
+ result: verification.valid,
207
+ errors: errors,
208
+ warnings: warnings,
209
+ verifiedAt: verification.verifiedAt
210
+ }
211
+ },
212
+ auditVerification: {
213
+ endpoint: 'POST /audit/right-verification',
214
+ data: {
215
+ tokenId: token.id,
216
+ rightType: verification.rightType,
217
+ issuer: verification.issuerDID,
218
+ subject: verification.subjectDID,
219
+ result: verification.valid,
220
+ verifiedAt: verification.verifiedAt
221
+ }
222
+ },
223
+ updateTokenStatus: verification.valid ? {
224
+ endpoint: 'PUT /rights/tokens/' + token.id + '/status',
225
+ data: {
226
+ status: 'VERIFIED',
227
+ verifiedAt: verification.verifiedAt
228
+ }
229
+ } : null
230
+ }
231
+ }
232
+
233
+ } catch (error) {
234
+ return {
235
+ success: false,
236
+ error: 'Verification preparation failed: ' + error.message
237
+ }
238
+ }
239
+ },
240
+
241
+ /**
242
+ * Prepare right token transfer for external processing
243
+ * @param {Object} token - Original right token
244
+ * @param {String} newOwnerDID - New owner DID
245
+ * @param {PrivateKey} currentOwnerKey - Current owner's private key
246
+ * @param {Object} options - Transfer options
247
+ * @returns {Object} Prepared transfer data
248
+ */
249
+ prepareRightTokenTransfer: function(token, newOwnerDID, currentOwnerKey, options) {
250
+ options = options || {}
251
+
252
+ $.checkArgument(token && typeof token === 'object', 'Invalid token')
253
+ $.checkArgument(typeof newOwnerDID === 'string', 'New owner DID must be string')
254
+ $.checkArgument(currentOwnerKey instanceof PrivateKey, 'Invalid current owner key')
255
+
256
+ try {
257
+ // Verify current token
258
+ var verification = this.prepareRightTokenVerification(token, {})
259
+ if (!verification.success || !verification.verification.valid) {
260
+ return {
261
+ success: false,
262
+ error: 'Cannot transfer invalid token: ' + verification.verification.errors.join(', ')
263
+ }
264
+ }
265
+
266
+ // Check transferability
267
+ if (!token.credentialSubject.transferable) {
268
+ return {
269
+ success: false,
270
+ error: 'Token is not transferable'
271
+ }
272
+ }
273
+
274
+ // Create transfer record
275
+ var transfer = {
276
+ '@context': [
277
+ 'https://www.w3.org/2018/credentials/v1',
278
+ 'https://smartledger.technology/contexts/ltp/v1'
279
+ ],
280
+ id: 'urn:uuid:' + this._generateUUID(),
281
+ type: ['VerifiableCredential', 'LegalRightTransfer'],
282
+ issuer: token.credentialSubject.id, // Current owner
283
+ issuanceDate: new Date().toISOString(),
284
+ credentialSubject: {
285
+ id: newOwnerDID,
286
+ originalToken: token.id,
287
+ transferFrom: token.credentialSubject.id,
288
+ transferTo: newOwnerDID,
289
+ transferDate: new Date().toISOString(),
290
+ transferReason: options.reason || 'ownership_transfer',
291
+ consideration: options.consideration || null
292
+ }
293
+ }
294
+
295
+ // Sign transfer with current owner key
296
+ var signedTransfer = this._signToken(transfer, currentOwnerKey)
297
+
298
+ // Create new token for new owner
299
+ var newToken = JSON.parse(JSON.stringify(token))
300
+ newToken.id = 'urn:uuid:' + this._generateUUID()
301
+ newToken.issuanceDate = new Date().toISOString()
302
+ newToken.credentialSubject.id = newOwnerDID
303
+ newToken.credentialSubject.transferHistory = newToken.credentialSubject.transferHistory || []
304
+ newToken.credentialSubject.transferHistory.push({
305
+ transferId: signedTransfer.id,
306
+ transferDate: signedTransfer.issuanceDate,
307
+ from: token.credentialSubject.id,
308
+ to: newOwnerDID
309
+ })
310
+
311
+ // Re-sign with current owner key (transfer authority)
312
+ delete newToken.proof
313
+ var newSignedToken = this._signToken(newToken, currentOwnerKey)
314
+
315
+ return {
316
+ success: true,
317
+ newToken: newSignedToken,
318
+ transferProof: signedTransfer,
319
+ transferId: signedTransfer.id,
320
+ externalOperations: {
321
+ recordTransfer: {
322
+ endpoint: 'POST /rights/transfers',
323
+ data: {
324
+ originalTokenId: token.id,
325
+ newTokenId: newSignedToken.id,
326
+ transferProof: signedTransfer,
327
+ fromOwner: token.credentialSubject.id,
328
+ toOwner: newOwnerDID,
329
+ transferDate: signedTransfer.issuanceDate
330
+ }
331
+ },
332
+ updateOwnership: {
333
+ endpoint: 'PUT /rights/tokens/' + token.id + '/ownership',
334
+ data: {
335
+ newOwner: newOwnerDID,
336
+ transferId: signedTransfer.id,
337
+ transferDate: signedTransfer.issuanceDate,
338
+ previousOwner: token.credentialSubject.id
339
+ }
340
+ },
341
+ notifyParties: {
342
+ endpoint: 'POST /notifications/right-transferred',
343
+ data: {
344
+ originalTokenId: token.id,
345
+ newTokenId: newSignedToken.id,
346
+ fromOwner: token.credentialSubject.id,
347
+ toOwner: newOwnerDID,
348
+ rightType: token.credentialSubject.rightType
349
+ }
350
+ },
351
+ auditTransfer: {
352
+ endpoint: 'POST /audit/right-transfer',
353
+ data: {
354
+ originalTokenId: token.id,
355
+ newTokenId: newSignedToken.id,
356
+ transferId: signedTransfer.id,
357
+ fromOwner: token.credentialSubject.id,
358
+ toOwner: newOwnerDID,
359
+ transferredAt: signedTransfer.issuanceDate
360
+ }
361
+ }
362
+ }
363
+ }
364
+
365
+ } catch (error) {
366
+ return {
367
+ success: false,
368
+ error: error.message
369
+ }
370
+ }
371
+ },
372
+
373
+ /**
374
+ * Prepare obligation token for external processing
375
+ * @param {Object} rightToken - Original right token
376
+ * @param {String} obligorDID - Who has the obligation
377
+ * @param {Object} obligation - Obligation details
378
+ * @param {PrivateKey} issuerKey - Issuer private key
379
+ * @returns {Object} Prepared obligation token data
380
+ */
381
+ prepareObligationToken: function(rightToken, obligorDID, obligation, issuerKey) {
382
+ $.checkArgument(rightToken && typeof rightToken === 'object', 'Invalid right token')
383
+ $.checkArgument(typeof obligorDID === 'string', 'Obligor DID must be string')
384
+ $.checkArgument(obligation && typeof obligation === 'object', 'Obligation must be object')
385
+ $.checkArgument(issuerKey instanceof PrivateKey, 'Invalid issuer key')
386
+
387
+ try {
388
+ var obligationToken = {
389
+ '@context': [
390
+ 'https://www.w3.org/2018/credentials/v1',
391
+ 'https://smartledger.technology/contexts/ltp/v1'
392
+ ],
393
+ id: 'urn:uuid:' + this._generateUUID(),
394
+ type: ['VerifiableCredential', 'LegalObligationToken'],
395
+ issuer: rightToken.issuer,
396
+ issuanceDate: new Date().toISOString(),
397
+ credentialSubject: {
398
+ id: obligorDID,
399
+ obligationType: 'correlative_obligation',
400
+ correlativeRight: rightToken.id,
401
+ rightHolder: rightToken.credentialSubject.id,
402
+ obligation: obligation,
403
+ jurisdiction: rightToken.credentialSubject.jurisdiction,
404
+ purpose: rightToken.credentialSubject.purpose
405
+ }
406
+ }
407
+
408
+ var signedObligation = this._signToken(obligationToken, issuerKey)
409
+
410
+ return {
411
+ success: true,
412
+ obligationToken: signedObligation,
413
+ correlativeRight: rightToken.id,
414
+ externalOperations: {
415
+ storeObligation: {
416
+ endpoint: 'POST /obligations/tokens',
417
+ data: {
418
+ obligationToken: signedObligation,
419
+ correlativeRightId: rightToken.id,
420
+ obligor: obligorDID,
421
+ rightHolder: rightToken.credentialSubject.id
422
+ }
423
+ },
424
+ linkToRight: {
425
+ endpoint: 'POST /rights/tokens/' + rightToken.id + '/obligations',
426
+ data: {
427
+ obligationId: signedObligation.id,
428
+ obligor: obligorDID,
429
+ obligationType: 'correlative_obligation'
430
+ }
431
+ },
432
+ notifyObligor: {
433
+ endpoint: 'POST /notifications/obligation-created',
434
+ data: {
435
+ obligationId: signedObligation.id,
436
+ obligor: obligorDID,
437
+ rightHolder: rightToken.credentialSubject.id,
438
+ correlativeRight: rightToken.id
439
+ }
440
+ }
441
+ }
442
+ }
443
+
444
+ } catch (error) {
445
+ return {
446
+ success: false,
447
+ error: error.message
448
+ }
449
+ }
450
+ },
451
+
452
+ /**
453
+ * Prepare right type validation for external systems
454
+ * @param {String} type - Right type to validate
455
+ * @returns {Object} Validation data
456
+ */
457
+ prepareRightTypeValidation: function(type) {
458
+ $.checkArgument(typeof type === 'string', 'Right type must be string')
459
+
460
+ var validTypes = Object.values(RightTypes)
461
+ var isValid = validTypes.includes(type)
462
+
463
+ return {
464
+ success: true,
465
+ validation: {
466
+ type: type,
467
+ valid: isValid,
468
+ availableTypes: validTypes,
469
+ category: this._categorizeRightType(type),
470
+ description: this._getRightTypeDescription(type)
471
+ },
472
+ externalOperations: {
473
+ validateType: {
474
+ endpoint: 'POST /rights/validate-type',
475
+ data: {
476
+ type: type,
477
+ valid: isValid
478
+ }
479
+ }
480
+ }
481
+ }
482
+ },
483
+
484
+ /**
485
+ * Categorize right type
486
+ * @private
487
+ */
488
+ _categorizeRightType: function(type) {
489
+ var categories = {
490
+ 'PropertyTitle': 'PROPERTY_RIGHT',
491
+ 'VehicleTitle': 'PROPERTY_RIGHT',
492
+ 'IntellectualProperty': 'IP_RIGHT',
493
+ 'MusicLicense': 'IP_RIGHT',
494
+ 'SoftwareLicense': 'IP_RIGHT',
495
+ 'FinancialInstrument': 'FINANCIAL_RIGHT',
496
+ 'PromissoryNote': 'FINANCIAL_RIGHT',
497
+ 'Bond': 'FINANCIAL_RIGHT',
498
+ 'EquityShare': 'FINANCIAL_RIGHT',
499
+ 'ProfessionalLicense': 'LICENSE_RIGHT',
500
+ 'RegulatoryPermit': 'LICENSE_RIGHT',
501
+ 'AccessRight': 'ACCESS_RIGHT',
502
+ 'VotingRight': 'GOVERNANCE_RIGHT',
503
+ 'RoyaltyRight': 'IP_RIGHT',
504
+ 'UsageRight': 'ACCESS_RIGHT'
505
+ }
506
+
507
+ return categories[type] || 'UNKNOWN'
508
+ },
509
+
510
+ /**
511
+ * Get right type description
512
+ * @private
513
+ */
514
+ _getRightTypeDescription: function(type) {
515
+ var descriptions = {
516
+ 'PropertyTitle': 'Legal ownership of real estate property',
517
+ 'VehicleTitle': 'Legal ownership of motor vehicle',
518
+ 'IntellectualProperty': 'Rights to intellectual property assets',
519
+ 'MusicLicense': 'License for music performance and usage',
520
+ 'SoftwareLicense': 'License for software usage and distribution',
521
+ 'FinancialInstrument': 'Rights related to financial instruments',
522
+ 'PromissoryNote': 'Promise to pay a specified amount',
523
+ 'Bond': 'Debt security representing loan',
524
+ 'EquityShare': 'Ownership stake in company',
525
+ 'ProfessionalLicense': 'License for professional practice',
526
+ 'RegulatoryPermit': 'Permit for regulated activities',
527
+ 'AccessRight': 'Right to access resources or locations',
528
+ 'VotingRight': 'Right to participate in governance',
529
+ 'RoyaltyRight': 'Right to receive royalty payments',
530
+ 'UsageRight': 'Right to use specific assets or services'
531
+ }
532
+
533
+ return descriptions[type] || 'Unknown right type'
534
+ },
535
+
536
+ /**
537
+ * Get available right types
538
+ * @returns {Object} Right types
539
+ */
540
+ getRightTypes: function() {
541
+ return RightTypes
542
+ },
543
+
544
+ /**
545
+ * Sign a token with private key
546
+ * @private
547
+ */
548
+ _signToken: function(token, privateKey) {
549
+ // Create canonical hash
550
+ var canonicalToken = this._canonicalizeToken(token)
551
+ var tokenHash = Hash.sha256(Buffer.from(canonicalToken))
552
+
553
+ // Sign with ECDSA
554
+ var ecdsa = new ECDSA()
555
+ ecdsa.hashbuf = tokenHash
556
+ ecdsa.privkey = privateKey
557
+ ecdsa.pubkey = privateKey.toPublicKey()
558
+
559
+ ecdsa.sign()
560
+ var signature = ecdsa.sig
561
+
562
+ // Create proof
563
+ var proof = {
564
+ type: 'EcdsaSecp256k1Signature2019',
565
+ created: new Date().toISOString(),
566
+ verificationMethod: 'did:smartledger:' + privateKey.toPublicKey().toString() + '#keys-1',
567
+ proofPurpose: 'assertionMethod',
568
+ jws: this._createJWS(tokenHash, signature)
569
+ }
570
+
571
+ // Add proof to token
572
+ var signedToken = JSON.parse(JSON.stringify(token))
573
+ signedToken.proof = proof
574
+ signedToken.tokenHash = tokenHash.toString('hex')
575
+
576
+ return signedToken
577
+ },
578
+
579
+ /**
580
+ * Sign a token with private key
581
+ * @private
582
+ */
583
+ _signToken: function(token, privateKey) {
584
+ var header = {
585
+ alg: 'ES256K',
586
+ typ: 'JWT'
587
+ }
588
+
589
+ var headerB64 = Buffer.from(JSON.stringify(header)).toString('base64url')
590
+ var payloadB64 = hash.toString('base64url')
591
+ var signatureB64 = signature.toDER().toString('base64url')
592
+
593
+ return headerB64 + '..' + signatureB64
594
+ },
595
+
596
+ /**
597
+ * Canonicalize token for hashing
598
+ * @private
599
+ */
600
+ _canonicalizeToken: function(token) {
601
+ // Remove proof and hash fields
602
+ var canonical = JSON.parse(JSON.stringify(token))
603
+ delete canonical.proof
604
+ delete canonical.tokenHash
605
+
606
+ // Sort keys recursively
607
+ return JSON.stringify(this._sortObjectKeys(canonical))
608
+ },
609
+
610
+ /**
611
+ * Sort object keys recursively
612
+ * @private
613
+ */
614
+ _sortObjectKeys: function(obj) {
615
+ if (Array.isArray(obj)) {
616
+ return obj.map(this._sortObjectKeys.bind(this))
617
+ } else if (obj !== null && typeof obj === 'object') {
618
+ var sorted = {}
619
+ Object.keys(obj).sort().forEach(function(key) {
620
+ sorted[key] = this._sortObjectKeys(obj[key])
621
+ }.bind(this))
622
+ return sorted
623
+ }
624
+ return obj
625
+ },
626
+
627
+ /**
628
+ * Validate token structure
629
+ * @private
630
+ */
631
+ _validateTokenStructure: function(token, errors) {
632
+ if (!token['@context']) {
633
+ errors.push('Missing @context')
634
+ }
635
+
636
+ if (!token.id) {
637
+ errors.push('Missing id')
638
+ }
639
+
640
+ if (!token.type || !Array.isArray(token.type)) {
641
+ errors.push('Missing or invalid type')
642
+ }
643
+
644
+ if (!token.issuer) {
645
+ errors.push('Missing issuer')
646
+ }
647
+
648
+ if (!token.issuanceDate) {
649
+ errors.push('Missing issuanceDate')
650
+ }
651
+
652
+ if (!token.credentialSubject) {
653
+ errors.push('Missing credentialSubject')
654
+ }
655
+
656
+ if (!token.proof) {
657
+ errors.push('Missing proof')
658
+ }
659
+ },
660
+
661
+ /**
662
+ * Verify token signature
663
+ * @private
664
+ */
665
+ _verifyTokenSignature: function(token, errors) {
666
+ try {
667
+ if (!token.proof || !token.proof.jws) {
668
+ errors.push('Missing signature proof')
669
+ return
670
+ }
671
+
672
+ // Recreate canonical hash
673
+ var canonicalToken = this._canonicalizeToken(token)
674
+ var expectedHash = Hash.sha256(Buffer.from(canonicalToken))
675
+
676
+ // Compare with stored hash if available
677
+ if (token.tokenHash && token.tokenHash !== expectedHash.toString('hex')) {
678
+ errors.push('Token hash mismatch')
679
+ return
680
+ }
681
+
682
+ // TODO: Verify JWS signature with issuer's public key
683
+ // This would require DID resolution to get the public key
684
+
685
+ } catch (error) {
686
+ errors.push('Signature verification failed: ' + error.message)
687
+ }
688
+ },
689
+
690
+ /**
691
+ * Validate temporal aspects
692
+ * @private
693
+ */
694
+ _validateTokenTemporal: function(token, errors, warnings) {
695
+ var now = new Date()
696
+ var issuanceDate = new Date(token.issuanceDate)
697
+
698
+ if (issuanceDate > now) {
699
+ errors.push('Token issued in the future')
700
+ }
701
+
702
+ if (token.credentialSubject.validFrom) {
703
+ var validFrom = new Date(token.credentialSubject.validFrom)
704
+ if (now < validFrom) {
705
+ warnings.push('Token not yet valid')
706
+ }
707
+ }
708
+
709
+ if (token.credentialSubject.validUntil) {
710
+ var validUntil = new Date(token.credentialSubject.validUntil)
711
+ if (now > validUntil) {
712
+ errors.push('Token expired')
713
+ }
714
+ }
715
+ },
716
+
717
+ /**
718
+ * Validate right type
719
+ * @private
720
+ */
721
+ _validateRightType: function(token, errors) {
722
+ if (!token.credentialSubject.rightType) {
723
+ errors.push('Missing rightType')
724
+ return
725
+ }
726
+
727
+ var validTypes = Object.values(RightTypes)
728
+ if (!validTypes.includes(token.credentialSubject.rightType)) {
729
+ errors.push('Invalid right type: ' + token.credentialSubject.rightType)
730
+ }
731
+ },
732
+
733
+ /**
734
+ * Validate jurisdiction
735
+ * @private
736
+ */
737
+ _validateJurisdiction: function(token, allowedJurisdictions, errors) {
738
+ if (!token.credentialSubject.jurisdiction) {
739
+ errors.push('Missing jurisdiction')
740
+ return
741
+ }
742
+
743
+ if (allowedJurisdictions && Array.isArray(allowedJurisdictions)) {
744
+ if (!allowedJurisdictions.includes(token.credentialSubject.jurisdiction)) {
745
+ errors.push('Jurisdiction not allowed: ' + token.credentialSubject.jurisdiction)
746
+ }
747
+ }
748
+ },
749
+
750
+ /**
751
+ * Generate UUID
752
+ * @private
753
+ */
754
+ _generateUUID: function() {
755
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
756
+ var r = Math.random() * 16 | 0
757
+ var v = c === 'x' ? r : (r & 0x3 | 0x8)
758
+ return v.toString(16)
759
+ })
760
+ }
761
+ }
762
+
763
+ // Export both the object and static methods for compatibility
764
+ RightToken.RightTypes = RightTypes
765
+ module.exports = RightToken