@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,461 @@
1
+ 'use strict'
2
+
3
+ var bsv = require('../../')
4
+ var DIDResolver = require('./did-resolver')
5
+ var PrivateKey = bsv.PrivateKey
6
+ var Hash = bsv.crypto.Hash
7
+ var ECDSA = bsv.crypto.ECDSA
8
+ var Signature = bsv.crypto.Signature
9
+ var $ = bsv.util.preconditions
10
+ var _ = require('../util/_')
11
+
12
+ /**
13
+ * AttestationSigner
14
+ *
15
+ * Creates and signs W3C Verifiable Credentials using SmartLedger cryptographic
16
+ * primitives. Supports JSON-LD format with embedded proofs compatible with
17
+ * the Global Digital Attestation Framework (GDAF).
18
+ *
19
+ * Features:
20
+ * - W3C VC Data Model 2.0 compliance
21
+ * - Deterministic JSON serialization
22
+ * - ECDSA signature proofs
23
+ * - Multiple credential types
24
+ * - Issuer DID integration
25
+ * - Schema validation
26
+ */
27
+
28
+ /**
29
+ * AttestationSigner constructor
30
+ * @param {PrivateKey|String} privateKey - Signing private key
31
+ * @param {Object} options - Configuration options
32
+ */
33
+ function AttestationSigner(privateKey, options) {
34
+ if (!(this instanceof AttestationSigner)) {
35
+ return new AttestationSigner(privateKey, options)
36
+ }
37
+
38
+ if (typeof privateKey === 'string') {
39
+ privateKey = PrivateKey.fromWIF(privateKey)
40
+ }
41
+
42
+ $.checkArgument(privateKey instanceof PrivateKey, 'Invalid private key')
43
+
44
+ this.privateKey = privateKey
45
+ this.publicKey = privateKey.toPublicKey()
46
+ this.options = options || {}
47
+ this.did = DIDResolver.fromPrivateKey(privateKey, this.options)
48
+
49
+ return this
50
+ }
51
+
52
+ /**
53
+ * Create canonical JSON string for signing
54
+ * @param {Object} obj - Object to canonicalize
55
+ * @returns {String} Canonical JSON string
56
+ */
57
+ AttestationSigner._canonicalizeJSON = function(obj) {
58
+ // Use deterministic JSON serialization
59
+ return JSON.stringify(obj, Object.keys(obj).sort())
60
+ }
61
+
62
+ /**
63
+ * Create hash of credential for signing
64
+ * @param {Object} credential - Credential object
65
+ * @returns {Buffer} SHA256 hash
66
+ */
67
+ AttestationSigner._hashCredential = function(credential) {
68
+ var canonical = AttestationSigner._canonicalizeJSON(credential)
69
+ return Hash.sha256(Buffer.from(canonical, 'utf8'))
70
+ }
71
+
72
+ /**
73
+ * Create base credential structure
74
+ * @param {Object} credentialSubject - Subject data
75
+ * @param {Object} options - Additional options
76
+ * @returns {Object} Base credential
77
+ */
78
+ AttestationSigner.prototype.createCredential = function(credentialSubject, options) {
79
+ options = options || {}
80
+
81
+ $.checkArgument(credentialSubject && typeof credentialSubject === 'object', 'Invalid credential subject')
82
+
83
+ var now = new Date().toISOString()
84
+ var credentialId = options.id || 'urn:uuid:' + this._generateUUID()
85
+
86
+ var credential = {
87
+ '@context': [
88
+ 'https://www.w3.org/2018/credentials/v1'
89
+ ],
90
+ id: credentialId,
91
+ type: ['VerifiableCredential'],
92
+ issuer: this.did,
93
+ issuanceDate: now,
94
+ credentialSubject: credentialSubject
95
+ }
96
+
97
+ // Add additional types
98
+ if (options.type) {
99
+ if (Array.isArray(options.type)) {
100
+ credential.type = credential.type.concat(options.type)
101
+ } else {
102
+ credential.type.push(options.type)
103
+ }
104
+ }
105
+
106
+ // Add additional contexts
107
+ if (options.context) {
108
+ if (Array.isArray(options.context)) {
109
+ credential['@context'] = credential['@context'].concat(options.context)
110
+ } else {
111
+ credential['@context'].push(options.context)
112
+ }
113
+ }
114
+
115
+ // Add expiration date
116
+ if (options.expirationDate) {
117
+ credential.expirationDate = options.expirationDate
118
+ }
119
+
120
+ // Add terms of use
121
+ if (options.termsOfUse) {
122
+ credential.termsOfUse = options.termsOfUse
123
+ }
124
+
125
+ // Add evidence
126
+ if (options.evidence) {
127
+ credential.evidence = options.evidence
128
+ }
129
+
130
+ // Add refresh service
131
+ if (options.refreshService) {
132
+ credential.refreshService = options.refreshService
133
+ }
134
+
135
+ return credential
136
+ }
137
+
138
+ /**
139
+ * Sign credential with ECDSA proof
140
+ * @param {Object} credential - Credential to sign
141
+ * @param {Object} options - Signing options
142
+ * @returns {Object} Signed credential
143
+ */
144
+ AttestationSigner.prototype.signCredential = function(credential, options) {
145
+ options = options || {}
146
+
147
+ $.checkArgument(credential && typeof credential === 'object', 'Invalid credential')
148
+
149
+ // Create a copy to avoid mutating original
150
+ var credentialCopy = JSON.parse(JSON.stringify(credential))
151
+
152
+ // Remove any existing proof
153
+ delete credentialCopy.proof
154
+
155
+ // Create canonical hash
156
+ var credentialHash = AttestationSigner._hashCredential(credentialCopy)
157
+
158
+ // Sign the hash
159
+ var ecdsa = new ECDSA()
160
+ ecdsa.hashbuf = credentialHash
161
+ ecdsa.privkey = this.privateKey
162
+ ecdsa.pubkey = this.publicKey
163
+
164
+ ecdsa.sign()
165
+ var signature = ecdsa.sig
166
+
167
+ var jwsSignature = this._createJWSSignature(credentialHash, signature)
168
+
169
+ // Create proof object
170
+ var proof = {
171
+ type: 'EcdsaSecp256k1Signature2019',
172
+ created: new Date().toISOString(),
173
+ verificationMethod: this.did + '#keys-1',
174
+ proofPurpose: options.proofPurpose || 'assertionMethod',
175
+ jws: jwsSignature
176
+ }
177
+
178
+ // Add challenge if provided
179
+ if (options.challenge) {
180
+ proof.challenge = options.challenge
181
+ }
182
+
183
+ // Add domain if provided
184
+ if (options.domain) {
185
+ proof.domain = options.domain
186
+ }
187
+
188
+ // Add proof to credential
189
+ var signedCredential = JSON.parse(JSON.stringify(credentialCopy))
190
+ signedCredential.proof = proof
191
+
192
+ // Add root hash for ZK proofs
193
+ signedCredential.rootHash = credentialHash.toString('hex')
194
+
195
+ return signedCredential
196
+ }
197
+
198
+ /**
199
+ * Create JWS-style signature
200
+ * @private
201
+ */
202
+ AttestationSigner.prototype._createJWSSignature = function(hash, signature) {
203
+ // Create minimal JWS header for ECDSA
204
+ var header = {
205
+ alg: 'ES256K',
206
+ typ: 'JWT'
207
+ }
208
+
209
+ var headerB64 = Buffer.from(JSON.stringify(header)).toString('base64url')
210
+ var payloadB64 = hash.toString('base64url')
211
+ var signatureB64 = signature.toDER().toString('base64url')
212
+
213
+ return headerB64 + '..' + signatureB64 // Empty payload for detached signature
214
+ }
215
+
216
+ /**
217
+ * Create Email Verified Credential
218
+ * @param {String} email - Email address
219
+ * @param {Object} options - Additional options
220
+ * @returns {Object} Signed credential
221
+ */
222
+ AttestationSigner.prototype.createEmailCredential = function(email, options) {
223
+ options = options || {}
224
+
225
+ $.checkArgument(typeof email === 'string' && email.includes('@'), 'Invalid email address')
226
+
227
+ var credentialSubject = {
228
+ id: options.subjectId || 'did:smartledger:' + Hash.sha256(Buffer.from(email)).toString('hex'),
229
+ email: email,
230
+ verified: true,
231
+ verificationMethod: 'email_verification',
232
+ verificationTimestamp: new Date().toISOString()
233
+ }
234
+
235
+ var credentialOptions = {
236
+ type: 'EmailVerifiedCredential',
237
+ context: 'https://smartledger.technology/contexts/email/v1',
238
+ ...options
239
+ }
240
+
241
+ var credential = this.createCredential(credentialSubject, credentialOptions)
242
+ return this.signCredential(credential, options)
243
+ }
244
+
245
+ /**
246
+ * Create Age Verification Credential
247
+ * @param {Number} age - Age to verify
248
+ * @param {Date} birthDate - Birth date (optional, for ZK proofs)
249
+ * @param {Object} options - Additional options
250
+ * @returns {Object} Signed credential
251
+ */
252
+ AttestationSigner.prototype.createAgeCredential = function(age, birthDate, options) {
253
+ options = options || {}
254
+
255
+ $.checkArgument(typeof age === 'number' && age > 0, 'Invalid age')
256
+
257
+ var credentialSubject = {
258
+ id: options.subjectId || 'urn:uuid:' + this._generateUUID(),
259
+ ageOver: age,
260
+ verified: true,
261
+ verificationMethod: 'age_verification'
262
+ }
263
+
264
+ // Include birth date hash for ZK proofs if provided
265
+ if (birthDate) {
266
+ credentialSubject.birthDateHash = Hash.sha256(Buffer.from(birthDate.toISOString())).toString('hex')
267
+ }
268
+
269
+ var credentialOptions = {
270
+ type: 'AgeVerifiedCredential',
271
+ context: 'https://smartledger.technology/contexts/age/v1',
272
+ ...options
273
+ }
274
+
275
+ var credential = this.createCredential(credentialSubject, credentialOptions)
276
+ return this.signCredential(credential, options)
277
+ }
278
+
279
+ /**
280
+ * Create KYC Verified Credential
281
+ * @param {Object} kycData - KYC verification data
282
+ * @param {Object} options - Additional options
283
+ * @returns {Object} Signed credential
284
+ */
285
+ AttestationSigner.prototype.createKYCCredential = function(kycData, options) {
286
+ options = options || {}
287
+
288
+ $.checkArgument(kycData && typeof kycData === 'object', 'Invalid KYC data')
289
+
290
+ var credentialSubject = {
291
+ id: options.subjectId || 'urn:uuid:' + this._generateUUID(),
292
+ kycLevel: kycData.level || 'basic',
293
+ verified: true,
294
+ verificationMethod: 'kyc_verification',
295
+ verificationTimestamp: new Date().toISOString(),
296
+ verifyingAuthority: kycData.authority || this.did
297
+ }
298
+
299
+ // Add hashed PII for privacy
300
+ if (kycData.firstName) {
301
+ credentialSubject.firstNameHash = Hash.sha256(Buffer.from(kycData.firstName)).toString('hex')
302
+ }
303
+
304
+ if (kycData.lastName) {
305
+ credentialSubject.lastNameHash = Hash.sha256(Buffer.from(kycData.lastName)).toString('hex')
306
+ }
307
+
308
+ if (kycData.ssn) {
309
+ credentialSubject.ssnHash = Hash.sha256(Buffer.from(kycData.ssn)).toString('hex')
310
+ }
311
+
312
+ var credentialOptions = {
313
+ type: 'KYCVerifiedCredential',
314
+ context: 'https://smartledger.technology/contexts/kyc/v1',
315
+ ...options
316
+ }
317
+
318
+ var credential = this.createCredential(credentialSubject, credentialOptions)
319
+ return this.signCredential(credential, options)
320
+ }
321
+
322
+ /**
323
+ * Create Organization Credential
324
+ * @param {Object} orgData - Organization data
325
+ * @param {Object} options - Additional options
326
+ * @returns {Object} Signed credential
327
+ */
328
+ AttestationSigner.prototype.createOrganizationCredential = function(orgData, options) {
329
+ options = options || {}
330
+
331
+ $.checkArgument(orgData && typeof orgData === 'object', 'Invalid organization data')
332
+
333
+ var credentialSubject = {
334
+ id: options.subjectId || 'did:smartledger:org:' + Hash.sha256(Buffer.from(orgData.name || '')).toString('hex'),
335
+ name: orgData.name,
336
+ type: orgData.type || 'Organization',
337
+ verified: true,
338
+ verificationMethod: 'organization_verification',
339
+ verificationTimestamp: new Date().toISOString()
340
+ }
341
+
342
+ // Add additional org fields
343
+ if (orgData.taxId) {
344
+ credentialSubject.taxIdHash = Hash.sha256(Buffer.from(orgData.taxId)).toString('hex')
345
+ }
346
+
347
+ if (orgData.incorporationState) {
348
+ credentialSubject.incorporationState = orgData.incorporationState
349
+ }
350
+
351
+ if (orgData.industry) {
352
+ credentialSubject.industry = orgData.industry
353
+ }
354
+
355
+ var credentialOptions = {
356
+ type: 'OrganizationCredential',
357
+ context: 'https://smartledger.technology/contexts/organization/v1',
358
+ ...options
359
+ }
360
+
361
+ var credential = this.createCredential(credentialSubject, credentialOptions)
362
+ return this.signCredential(credential, options)
363
+ }
364
+
365
+ /**
366
+ * Generate UUID v4
367
+ * @private
368
+ */
369
+ AttestationSigner.prototype._generateUUID = function() {
370
+ var random = bsv.crypto.Random.getRandomBuffer(16)
371
+
372
+ // Set version (4) and variant bits
373
+ random[6] = (random[6] & 0x0f) | 0x40
374
+ random[8] = (random[8] & 0x3f) | 0x80
375
+
376
+ var hex = random.toString('hex')
377
+ return [
378
+ hex.substring(0, 8),
379
+ hex.substring(8, 12),
380
+ hex.substring(12, 16),
381
+ hex.substring(16, 20),
382
+ hex.substring(20, 32)
383
+ ].join('-')
384
+ }
385
+
386
+ /**
387
+ * Create presentation of multiple credentials
388
+ * @param {Array} credentials - Array of signed credentials
389
+ * @param {Object} options - Presentation options
390
+ * @returns {Object} Signed presentation
391
+ */
392
+ AttestationSigner.prototype.createPresentation = function(credentials, options) {
393
+ options = options || {}
394
+
395
+ $.checkArgument(Array.isArray(credentials), 'Credentials must be an array')
396
+
397
+ var presentation = {
398
+ '@context': [
399
+ 'https://www.w3.org/2018/credentials/v1'
400
+ ],
401
+ type: ['VerifiablePresentation'],
402
+ id: options.id || 'urn:uuid:' + this._generateUUID(),
403
+ holder: this.did,
404
+ verifiableCredential: credentials
405
+ }
406
+
407
+ // Add additional contexts
408
+ if (options.context) {
409
+ if (Array.isArray(options.context)) {
410
+ presentation['@context'] = presentation['@context'].concat(options.context)
411
+ } else {
412
+ presentation['@context'].push(options.context)
413
+ }
414
+ }
415
+
416
+ // Sign the presentation
417
+ var presentationHash = AttestationSigner._hashCredential(presentation)
418
+
419
+ var ecdsa = new ECDSA()
420
+ ecdsa.hashbuf = presentationHash
421
+ ecdsa.privkey = this.privateKey
422
+ ecdsa.pubkey = this.publicKey
423
+
424
+ ecdsa.sign()
425
+ var signature = ecdsa.sig
426
+ var jwsSignature = this._createJWSSignature(presentationHash, signature)
427
+
428
+ var proof = {
429
+ type: 'EcdsaSecp256k1Signature2019',
430
+ created: new Date().toISOString(),
431
+ verificationMethod: this.did + '#keys-1',
432
+ proofPurpose: 'authentication',
433
+ jws: jwsSignature
434
+ }
435
+
436
+ if (options.challenge) {
437
+ proof.challenge = options.challenge
438
+ }
439
+
440
+ if (options.domain) {
441
+ proof.domain = options.domain
442
+ }
443
+
444
+ presentation.proof = proof
445
+
446
+ return presentation
447
+ }
448
+
449
+ /**
450
+ * Get issuer information
451
+ * @returns {Object} Issuer information
452
+ */
453
+ AttestationSigner.prototype.getIssuerInfo = function() {
454
+ return {
455
+ did: this.did,
456
+ publicKey: this.publicKey.toString('hex'),
457
+ verificationMethod: this.did + '#keys-1'
458
+ }
459
+ }
460
+
461
+ module.exports = AttestationSigner