smartledger-bsv 3.2.1 → 3.3.1

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,600 @@
1
+ 'use strict'
2
+
3
+ var bsv = require('../../')
4
+ var DIDResolver = require('./did-resolver')
5
+ var AttestationSigner = require('./attestation-signer')
6
+ var PublicKey = bsv.PublicKey
7
+ var Hash = bsv.crypto.Hash
8
+ var ECDSA = bsv.crypto.ECDSA
9
+ var Signature = bsv.crypto.Signature
10
+ var $ = bsv.util.preconditions
11
+
12
+ /**
13
+ * AttestationVerifier
14
+ *
15
+ * Verifies W3C Verifiable Credentials and Presentations created by
16
+ * AttestationSigner. Provides comprehensive validation including:
17
+ * - Signature verification
18
+ * - DID resolution and validation
19
+ * - Schema compliance checking
20
+ * - Temporal validity (expiration, issuance dates)
21
+ * - Trust chain validation
22
+ */
23
+
24
+ /**
25
+ * AttestationVerifier constructor
26
+ * @param {Object} options - Configuration options
27
+ */
28
+ function AttestationVerifier(options) {
29
+ if (!(this instanceof AttestationVerifier)) {
30
+ return new AttestationVerifier(options)
31
+ }
32
+
33
+ this.options = options || {}
34
+ this.trustedIssuers = this.options.trustedIssuers || []
35
+
36
+ return this
37
+ }
38
+
39
+ /**
40
+ * Verify a Verifiable Credential
41
+ * @param {Object} credential - Credential to verify
42
+ * @param {Object} options - Verification options
43
+ * @returns {Promise<Object>} Verification result
44
+ */
45
+ AttestationVerifier.verifyCredential = async function(credential, options) {
46
+ options = options || {}
47
+
48
+ try {
49
+ $.checkArgument(credential && typeof credential === 'object', 'Invalid credential')
50
+
51
+ var result = {
52
+ valid: false,
53
+ errors: [],
54
+ warnings: [],
55
+ checks: {
56
+ structure: false,
57
+ signature: false,
58
+ issuer: false,
59
+ temporal: false,
60
+ schema: false
61
+ }
62
+ }
63
+
64
+ // 1. Structure validation
65
+ var structureCheck = AttestationVerifier._validateStructure(credential)
66
+ result.checks.structure = structureCheck.valid
67
+ if (!structureCheck.valid) {
68
+ result.errors = result.errors.concat(structureCheck.errors)
69
+ }
70
+
71
+ // 2. Signature verification
72
+ var signatureCheck = await AttestationVerifier._verifySignature(credential)
73
+ result.checks.signature = signatureCheck.valid
74
+ if (!signatureCheck.valid) {
75
+ result.errors = result.errors.concat(signatureCheck.errors)
76
+ } else {
77
+ result.issuerDID = signatureCheck.issuerDID
78
+ result.verificationMethod = signatureCheck.verificationMethod
79
+ }
80
+
81
+ // 3. Issuer validation
82
+ var issuerCheck = await AttestationVerifier._validateIssuer(credential, options)
83
+ result.checks.issuer = issuerCheck.valid
84
+ if (!issuerCheck.valid) {
85
+ result.errors = result.errors.concat(issuerCheck.errors)
86
+ }
87
+ if (issuerCheck.warnings) {
88
+ result.warnings = result.warnings.concat(issuerCheck.warnings)
89
+ }
90
+
91
+ // 4. Temporal validation
92
+ var temporalCheck = AttestationVerifier._validateTemporal(credential)
93
+ result.checks.temporal = temporalCheck.valid
94
+ if (!temporalCheck.valid) {
95
+ result.errors = result.errors.concat(temporalCheck.errors)
96
+ }
97
+ if (temporalCheck.warnings) {
98
+ result.warnings = result.warnings.concat(temporalCheck.warnings)
99
+ }
100
+
101
+ // 5. Schema validation (if schema provided)
102
+ if (options.schema) {
103
+ var schemaCheck = AttestationVerifier._validateSchema(credential, options.schema)
104
+ result.checks.schema = schemaCheck.valid
105
+ if (!schemaCheck.valid) {
106
+ result.errors = result.errors.concat(schemaCheck.errors)
107
+ }
108
+ } else {
109
+ result.checks.schema = true // Skip if no schema provided
110
+ }
111
+
112
+ // Overall validity
113
+ result.valid = Object.values(result.checks).every(check => check === true)
114
+
115
+ return result
116
+
117
+ } catch (error) {
118
+ return {
119
+ valid: false,
120
+ errors: ['Verification failed: ' + error.message],
121
+ warnings: [],
122
+ checks: {
123
+ structure: false,
124
+ signature: false,
125
+ issuer: false,
126
+ temporal: false,
127
+ schema: false
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Verify a Verifiable Presentation
135
+ * @param {Object} presentation - Presentation to verify
136
+ * @param {Object} options - Verification options
137
+ * @returns {Promise<Object>} Verification result
138
+ */
139
+ AttestationVerifier.verifyPresentation = async function(presentation, options) {
140
+ options = options || {}
141
+
142
+ try {
143
+ $.checkArgument(presentation && typeof presentation === 'object', 'Invalid presentation')
144
+
145
+ var result = {
146
+ valid: false,
147
+ errors: [],
148
+ warnings: [],
149
+ credentialResults: [],
150
+ presentationValid: false
151
+ }
152
+
153
+ // Verify presentation structure
154
+ if (!presentation.type || !presentation.type.includes('VerifiablePresentation')) {
155
+ result.errors.push('Invalid presentation type')
156
+ return result
157
+ }
158
+
159
+ if (!presentation.holder) {
160
+ result.errors.push('Missing presentation holder')
161
+ return result
162
+ }
163
+
164
+ // Verify presentation signature
165
+ var presentationCheck = await AttestationVerifier._verifyPresentationSignature(presentation)
166
+ result.presentationValid = presentationCheck.valid
167
+ if (!presentationCheck.valid) {
168
+ result.errors = result.errors.concat(presentationCheck.errors)
169
+ }
170
+
171
+ // Verify each credential in the presentation
172
+ if (presentation.verifiableCredential && Array.isArray(presentation.verifiableCredential)) {
173
+ for (var i = 0; i < presentation.verifiableCredential.length; i++) {
174
+ var credential = presentation.verifiableCredential[i]
175
+ var credentialResult = await AttestationVerifier.verifyCredential(credential, options)
176
+ result.credentialResults.push({
177
+ index: i,
178
+ result: credentialResult
179
+ })
180
+
181
+ if (!credentialResult.valid) {
182
+ result.errors.push('Credential ' + i + ' is invalid')
183
+ }
184
+ }
185
+ }
186
+
187
+ // Overall validity
188
+ var allCredentialsValid = result.credentialResults.every(cr => cr.result.valid)
189
+ result.valid = result.presentationValid && allCredentialsValid
190
+
191
+ return result
192
+
193
+ } catch (error) {
194
+ return {
195
+ valid: false,
196
+ errors: ['Presentation verification failed: ' + error.message],
197
+ warnings: [],
198
+ credentialResults: [],
199
+ presentationValid: false
200
+ }
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Validate credential structure
206
+ * @private
207
+ */
208
+ AttestationVerifier._validateStructure = function(credential) {
209
+ var errors = []
210
+
211
+ // Required fields
212
+ if (!credential['@context']) {
213
+ errors.push('Missing @context')
214
+ } else if (!Array.isArray(credential['@context'])) {
215
+ errors.push('@context must be an array')
216
+ } else if (!credential['@context'].includes('https://www.w3.org/2018/credentials/v1')) {
217
+ errors.push('Missing required W3C credentials context')
218
+ }
219
+
220
+ if (!credential.type) {
221
+ errors.push('Missing type')
222
+ } else if (!Array.isArray(credential.type)) {
223
+ errors.push('type must be an array')
224
+ } else if (!credential.type.includes('VerifiableCredential')) {
225
+ errors.push('Must include VerifiableCredential type')
226
+ }
227
+
228
+ if (!credential.issuer) {
229
+ errors.push('Missing issuer')
230
+ }
231
+
232
+ if (!credential.issuanceDate) {
233
+ errors.push('Missing issuanceDate')
234
+ }
235
+
236
+ if (!credential.credentialSubject) {
237
+ errors.push('Missing credentialSubject')
238
+ }
239
+
240
+ if (!credential.proof) {
241
+ errors.push('Missing proof')
242
+ }
243
+
244
+ return {
245
+ valid: errors.length === 0,
246
+ errors: errors
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Verify credential signature
252
+ * @private
253
+ */
254
+ AttestationVerifier._verifySignature = async function(credential) {
255
+ try {
256
+ var proof = credential.proof
257
+ if (!proof) {
258
+ return { valid: false, errors: ['Missing proof'] }
259
+ }
260
+
261
+ if (proof.type !== 'EcdsaSecp256k1Signature2019') {
262
+ return { valid: false, errors: ['Unsupported proof type: ' + proof.type] }
263
+ }
264
+
265
+ if (!proof.verificationMethod) {
266
+ return { valid: false, errors: ['Missing verification method'] }
267
+ }
268
+
269
+ if (!proof.jws) {
270
+ return { valid: false, errors: ['Missing JWS signature'] }
271
+ }
272
+
273
+ // Extract DID from verification method
274
+ var verificationMethod = proof.verificationMethod
275
+ var did = verificationMethod.split('#')[0]
276
+
277
+ // Get public key from DID
278
+ var publicKey = DIDResolver.getPublicKey(did)
279
+
280
+ // Recreate credential without proof for verification
281
+ var credentialCopy = JSON.parse(JSON.stringify(credential))
282
+ delete credentialCopy.proof
283
+ delete credentialCopy.rootHash
284
+
285
+ // Create hash
286
+ var credentialHash = AttestationSigner._hashCredential(credentialCopy)
287
+
288
+ // Verify signature
289
+ var signature = AttestationVerifier._parseJWSSignature(proof.jws)
290
+
291
+ var ecdsa = new ECDSA()
292
+ ecdsa.hashbuf = credentialHash
293
+ ecdsa.pubkey = publicKey
294
+ ecdsa.sig = signature
295
+
296
+ var valid = ecdsa.verify()
297
+
298
+ if (valid) {
299
+ return {
300
+ valid: true,
301
+ issuerDID: did,
302
+ verificationMethod: verificationMethod
303
+ }
304
+ } else {
305
+ return { valid: false, errors: ['Signature verification failed'] }
306
+ }
307
+
308
+ } catch (error) {
309
+ return { valid: false, errors: ['Signature verification error: ' + error.message] }
310
+ }
311
+ }
312
+
313
+ /**
314
+ * Parse JWS signature
315
+ * @private
316
+ */
317
+ AttestationVerifier._parseJWSSignature = function(jws) {
318
+ var parts = jws.split('.')
319
+ if (parts.length !== 3) {
320
+ throw new Error('Invalid JWS format')
321
+ }
322
+
323
+ var signatureB64 = parts[2]
324
+ var signatureBuffer = Buffer.from(signatureB64, 'base64url')
325
+
326
+ return Signature.fromDER(signatureBuffer)
327
+ }
328
+
329
+ /**
330
+ * Verify presentation signature
331
+ * @private
332
+ */
333
+ AttestationVerifier._verifyPresentationSignature = async function(presentation) {
334
+ try {
335
+ var proof = presentation.proof
336
+ if (!proof) {
337
+ return { valid: false, errors: ['Missing presentation proof'] }
338
+ }
339
+
340
+ // Extract holder DID
341
+ var holderDID = presentation.holder
342
+ var publicKey = DIDResolver.getPublicKey(holderDID)
343
+
344
+ // Recreate presentation without proof
345
+ var presentationCopy = JSON.parse(JSON.stringify(presentation))
346
+ delete presentationCopy.proof
347
+
348
+ // Create hash
349
+ var presentationHash = AttestationSigner._hashCredential(presentationCopy)
350
+
351
+ // Verify signature
352
+ var signature = AttestationVerifier._parseJWSSignature(proof.jws)
353
+
354
+ var ecdsa = new ECDSA()
355
+ ecdsa.hashbuf = presentationHash
356
+ ecdsa.pubkey = publicKey
357
+ ecdsa.sig = signature
358
+
359
+ var valid = ecdsa.verify()
360
+
361
+ return {
362
+ valid: valid,
363
+ errors: valid ? [] : ['Presentation signature verification failed']
364
+ }
365
+
366
+ } catch (error) {
367
+ return { valid: false, errors: ['Presentation signature error: ' + error.message] }
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Validate issuer
373
+ * @private
374
+ */
375
+ AttestationVerifier._validateIssuer = async function(credential, options) {
376
+ var errors = []
377
+ var warnings = []
378
+
379
+ try {
380
+ var issuer = credential.issuer
381
+
382
+ // Validate DID format
383
+ if (!DIDResolver.isValidDID(issuer)) {
384
+ errors.push('Invalid issuer DID format')
385
+ return { valid: false, errors: errors }
386
+ }
387
+
388
+ // Resolve DID document
389
+ var resolution = await DIDResolver.resolve(issuer)
390
+ if (!resolution.didDocument) {
391
+ errors.push('Unable to resolve issuer DID')
392
+ return { valid: false, errors: errors }
393
+ }
394
+
395
+ // Check if issuer is in trusted list
396
+ if (options.trustedIssuers && Array.isArray(options.trustedIssuers)) {
397
+ if (!options.trustedIssuers.includes(issuer)) {
398
+ warnings.push('Issuer not in trusted list')
399
+ }
400
+ }
401
+
402
+ return {
403
+ valid: errors.length === 0,
404
+ errors: errors,
405
+ warnings: warnings
406
+ }
407
+
408
+ } catch (error) {
409
+ return {
410
+ valid: false,
411
+ errors: ['Issuer validation error: ' + error.message],
412
+ warnings: warnings
413
+ }
414
+ }
415
+ }
416
+
417
+ /**
418
+ * Validate temporal constraints
419
+ * @private
420
+ */
421
+ AttestationVerifier._validateTemporal = function(credential) {
422
+ var errors = []
423
+ var warnings = []
424
+ var now = new Date()
425
+
426
+ // Validate issuance date
427
+ if (credential.issuanceDate) {
428
+ var issuanceDate = new Date(credential.issuanceDate)
429
+ if (isNaN(issuanceDate.getTime())) {
430
+ errors.push('Invalid issuanceDate format')
431
+ } else if (issuanceDate > now) {
432
+ errors.push('Credential issued in the future')
433
+ }
434
+ }
435
+
436
+ // Validate expiration date
437
+ if (credential.expirationDate) {
438
+ var expirationDate = new Date(credential.expirationDate)
439
+ if (isNaN(expirationDate.getTime())) {
440
+ errors.push('Invalid expirationDate format')
441
+ } else if (expirationDate <= now) {
442
+ errors.push('Credential has expired')
443
+ } else if (expirationDate <= new Date(now.getTime() + 24 * 60 * 60 * 1000)) {
444
+ warnings.push('Credential expires within 24 hours')
445
+ }
446
+ }
447
+
448
+ return {
449
+ valid: errors.length === 0,
450
+ errors: errors,
451
+ warnings: warnings
452
+ }
453
+ }
454
+
455
+ /**
456
+ * Validate schema compliance
457
+ * @private
458
+ */
459
+ AttestationVerifier._validateSchema = function(credential, schema) {
460
+ var errors = []
461
+
462
+ // Basic schema validation (can be extended with JSON Schema validator)
463
+ if (schema.requiredFields) {
464
+ schema.requiredFields.forEach(function(field) {
465
+ if (!AttestationVerifier._getNestedProperty(credential, field)) {
466
+ errors.push('Missing required field: ' + field)
467
+ }
468
+ })
469
+ }
470
+
471
+ if (schema.requiredTypes) {
472
+ var hasRequiredType = schema.requiredTypes.some(function(type) {
473
+ return credential.type && credential.type.includes(type)
474
+ })
475
+
476
+ if (!hasRequiredType) {
477
+ errors.push('Missing required credential type')
478
+ }
479
+ }
480
+
481
+ return {
482
+ valid: errors.length === 0,
483
+ errors: errors
484
+ }
485
+ }
486
+
487
+ /**
488
+ * Get nested property from object
489
+ * @private
490
+ */
491
+ AttestationVerifier._getNestedProperty = function(obj, path) {
492
+ return path.split('.').reduce(function(current, prop) {
493
+ return current && current[prop]
494
+ }, obj)
495
+ }
496
+
497
+ /**
498
+ * Verify credential hash integrity
499
+ * @param {Object} credential - Credential to verify
500
+ * @returns {Boolean} True if hash matches
501
+ */
502
+ AttestationVerifier.verifyCredentialHash = function(credential) {
503
+ try {
504
+ if (!credential.rootHash) {
505
+ return false
506
+ }
507
+
508
+ var credentialCopy = JSON.parse(JSON.stringify(credential))
509
+ delete credentialCopy.proof
510
+ delete credentialCopy.rootHash
511
+
512
+ var computedHash = AttestationSigner._hashCredential(credentialCopy)
513
+ var storedHash = Buffer.from(credential.rootHash, 'hex')
514
+
515
+ return Buffer.compare(computedHash, storedHash) === 0
516
+ } catch (error) {
517
+ return false
518
+ }
519
+ }
520
+
521
+ /**
522
+ * Extract claims from credential
523
+ * @param {Object} credential - Credential
524
+ * @returns {Object} Extracted claims
525
+ */
526
+ AttestationVerifier.extractClaims = function(credential) {
527
+ try {
528
+ var claims = {
529
+ issuer: credential.issuer,
530
+ subject: credential.credentialSubject.id || 'unknown',
531
+ types: credential.type || [],
532
+ issuanceDate: credential.issuanceDate,
533
+ expirationDate: credential.expirationDate,
534
+ claims: {}
535
+ }
536
+
537
+ // Extract subject claims
538
+ Object.keys(credential.credentialSubject).forEach(function(key) {
539
+ if (key !== 'id') {
540
+ claims.claims[key] = credential.credentialSubject[key]
541
+ }
542
+ })
543
+
544
+ return claims
545
+ } catch (error) {
546
+ return null
547
+ }
548
+ }
549
+
550
+ /**
551
+ * Create verification report
552
+ * @param {Object} verificationResult - Result from verifyCredential
553
+ * @returns {String} Human-readable report
554
+ */
555
+ AttestationVerifier.createReport = function(verificationResult) {
556
+ var report = []
557
+
558
+ report.push('=== Credential Verification Report ===')
559
+ report.push('Overall Status: ' + (verificationResult.valid ? 'VALID' : 'INVALID'))
560
+ report.push('')
561
+
562
+ // Checks
563
+ report.push('Verification Checks:')
564
+ Object.keys(verificationResult.checks).forEach(function(check) {
565
+ var status = verificationResult.checks[check] ? '✓' : '✗'
566
+ report.push(' ' + status + ' ' + check.charAt(0).toUpperCase() + check.slice(1))
567
+ })
568
+ report.push('')
569
+
570
+ // Errors
571
+ if (verificationResult.errors.length > 0) {
572
+ report.push('Errors:')
573
+ verificationResult.errors.forEach(function(error) {
574
+ report.push(' • ' + error)
575
+ })
576
+ report.push('')
577
+ }
578
+
579
+ // Warnings
580
+ if (verificationResult.warnings.length > 0) {
581
+ report.push('Warnings:')
582
+ verificationResult.warnings.forEach(function(warning) {
583
+ report.push(' • ' + warning)
584
+ })
585
+ report.push('')
586
+ }
587
+
588
+ // Issuer info
589
+ if (verificationResult.issuerDID) {
590
+ report.push('Issuer: ' + verificationResult.issuerDID)
591
+ }
592
+
593
+ if (verificationResult.verificationMethod) {
594
+ report.push('Verification Method: ' + verificationResult.verificationMethod)
595
+ }
596
+
597
+ return report.join('\n')
598
+ }
599
+
600
+ module.exports = AttestationVerifier