@smartledger/bsv 3.3.5 → 3.4.0

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.
@@ -0,0 +1,21 @@
1
+ var path = require('path')
2
+
3
+ module.exports = {
4
+ target: 'web',
5
+ mode: 'production',
6
+ entry: './anchor-entry.js',
7
+ output: {
8
+ path: path.resolve(__dirname, '..'),
9
+ filename: 'bsv-anchor.min.js',
10
+ library: 'bsvAnchor',
11
+ libraryTarget: 'umd'
12
+ },
13
+ node: {
14
+ crypto: true,
15
+ stream: true,
16
+ buffer: true
17
+ },
18
+ node: {
19
+ Buffer: true
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ var path = require('path')
2
+
3
+ module.exports = {
4
+ target: 'web',
5
+ mode: 'production',
6
+ entry: './didweb-entry.js',
7
+ output: {
8
+ path: path.resolve(__dirname, '..'),
9
+ filename: 'bsv-didweb.min.js',
10
+ library: 'bsvDidWeb',
11
+ libraryTarget: 'umd'
12
+ },
13
+ node: {
14
+ crypto: true,
15
+ stream: true,
16
+ buffer: true
17
+ },
18
+ node: {
19
+ Buffer: true
20
+ }
21
+ }
@@ -0,0 +1,22 @@
1
+ var path = require('path')
2
+
3
+ module.exports = {
4
+ target: 'web',
5
+ mode: 'production',
6
+ entry: './statuslist-entry.js',
7
+ output: {
8
+ path: path.resolve(__dirname, '..'),
9
+ filename: 'bsv-statuslist.min.js',
10
+ library: 'bsvStatusList',
11
+ libraryTarget: 'umd'
12
+ },
13
+ node: {
14
+ crypto: true,
15
+ stream: true,
16
+ buffer: true,
17
+ zlib: true
18
+ },
19
+ node: {
20
+ Buffer: true
21
+ }
22
+ }
@@ -0,0 +1,21 @@
1
+ var path = require('path')
2
+
3
+ module.exports = {
4
+ target: 'web',
5
+ mode: 'production',
6
+ entry: './vcjwt-entry.js',
7
+ output: {
8
+ path: path.resolve(__dirname, '..'),
9
+ filename: 'bsv-vcjwt.min.js',
10
+ library: 'bsvVcJwt',
11
+ libraryTarget: 'umd'
12
+ },
13
+ node: {
14
+ crypto: true,
15
+ stream: true,
16
+ buffer: true
17
+ },
18
+ node: {
19
+ Buffer: true
20
+ }
21
+ }
@@ -182,7 +182,7 @@
182
182
  </div>
183
183
 
184
184
  <!-- Load SmartLedger-BSV from CDN -->
185
- <script src="https://unpkg.com/smartledger-bsv@3.3.4/bsv.bundle.js"></script>
185
+ <script src="https://unpkg.com/smartledger-bsv@3.3.5/bsv.bundle.js"></script>
186
186
 
187
187
  <script>
188
188
  let bsv;
@@ -0,0 +1 @@
1
+ module.exports = require('./lib/didweb')
@@ -606,11 +606,11 @@ Provides hardened Bitcoin SV primitives + SmartLedger security modules.
606
606
 
607
607
  - **GitHub Repository** - https://github.com/codenlighten/smartledger-bsv🔒 *“Verified cryptographic fabric + transaction interpreter.”*
608
608
 
609
- - **Developer Documentation** - https://docs.smartledger.io
609
+ - **Developer Documentation** - https://docs.smartledger.technology
610
610
 
611
611
  - **Community Discord** - https://discord.gg/smartledger---
612
612
 
613
- - **Standards Working Group** - https://standards.smartledger.io
613
+ - **Standards Working Group** - https://standards.smartledger.technology
614
614
 
615
615
  ## 2️⃣ Identity Layer: GDAF (Global Digital Attestation Framework)
616
616
 
@@ -903,7 +903,7 @@ SmartLedger-BSV/
903
903
 
904
904
  ### 🔹 **Minified CDN Build**
905
905
 
906
- `https://cdn.smartledger.io/smartledger-bsv.min.js`
906
+ `https://cdn.smartledger.technology/smartledger-bsv.min.js`
907
907
  Provides browser-side access to the same hardened primitives used in Node:
908
908
 
909
909
  ```js
package/index.js CHANGED
@@ -136,6 +136,34 @@ if (typeof window === 'undefined' && typeof require === 'function') {
136
136
  // Global Digital Attestation Framework (GDAF)
137
137
  bsv.GDAF = require('./lib/gdaf')
138
138
 
139
+ // DID:web Module (W3C standards-based DIDs)
140
+ try {
141
+ bsv.DIDWeb = require('./lib/didweb')
142
+ } catch (e) {
143
+ // DIDWeb module not available - use standalone bsv-didweb.min.js
144
+ }
145
+
146
+ // VC-JWT Module (W3C Verifiable Credentials)
147
+ try {
148
+ bsv.VcJwt = require('./lib/vcjwt')
149
+ } catch (e) {
150
+ // VcJwt module not available - use standalone bsv-vcjwt.min.js
151
+ }
152
+
153
+ // StatusList2021 Module (Credential revocation)
154
+ try {
155
+ bsv.StatusList = require('./lib/statuslist')
156
+ } catch (e) {
157
+ // StatusList module not available - use standalone bsv-statuslist.min.js
158
+ }
159
+
160
+ // Anchor Module (BSV hash anchoring)
161
+ try {
162
+ bsv.Anchor = require('./lib/anchor')
163
+ } catch (e) {
164
+ // Anchor module not available - use standalone bsv-anchor.min.js
165
+ }
166
+
139
167
  // GDAF Direct Access Methods (for easier developer experience)
140
168
  bsv.createDID = function(publicKey) {
141
169
  var gdaf = new bsv.GDAF()
@@ -0,0 +1,102 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * BSV Anchor Module
5
+ * Hash anchoring helpers for on-chain evidence (no PII)
6
+ */
7
+
8
+ var crypto = require('crypto')
9
+
10
+ // SHA-256 hex hash
11
+ function sha256Hex(data) {
12
+ var buffer
13
+ if (typeof data === 'string') {
14
+ buffer = Buffer.from(data, 'utf8')
15
+ } else if (Buffer.isBuffer(data)) {
16
+ buffer = data
17
+ } else if (data instanceof Uint8Array) {
18
+ buffer = Buffer.from(data)
19
+ } else {
20
+ throw new Error('Data must be string, Buffer, or Uint8Array')
21
+ }
22
+
23
+ return crypto.createHash('sha256').update(buffer).digest('hex')
24
+ }
25
+
26
+ // Build anchor payload for OP_RETURN
27
+ function buildAnchorPayload(params) {
28
+ if (!params.kind || !params.hash || !params.issuerDid) {
29
+ throw new Error('kind, hash, and issuerDid are required')
30
+ }
31
+
32
+ var validKinds = ['VC_ANCHOR_SHA256', 'STATUSLIST_SHA256', 'PRESENTATION_SHA256']
33
+ if (validKinds.indexOf(params.kind) === -1) {
34
+ throw new Error('Invalid kind. Must be one of: ' + validKinds.join(', '))
35
+ }
36
+
37
+ // Validate hash format (64 hex characters)
38
+ if (!/^[a-fA-F0-9]{64}$/.test(params.hash)) {
39
+ throw new Error('Invalid hash format. Must be 64 hex characters')
40
+ }
41
+
42
+ var payload = {
43
+ protocol: 'SmartLedger',
44
+ version: '1.0',
45
+ type: params.kind,
46
+ hash: params.hash,
47
+ issuer: params.issuerDid,
48
+ timestamp: params.issuedAt || new Date().toISOString()
49
+ }
50
+
51
+ return {
52
+ json: JSON.stringify(payload)
53
+ }
54
+ }
55
+
56
+ // Verify anchor hash against original data
57
+ function verifyAnchorHash(originalData, anchorHash) {
58
+ var computed = sha256Hex(originalData)
59
+ return computed === anchorHash
60
+ }
61
+
62
+ // Extract anchor info from OP_RETURN data
63
+ function parseAnchorPayload(opReturnData) {
64
+ try {
65
+ var parsed = JSON.parse(opReturnData)
66
+
67
+ if (parsed.protocol !== 'SmartLedger') {
68
+ return { valid: false, error: 'Invalid protocol' }
69
+ }
70
+
71
+ var validTypes = ['VC_ANCHOR_SHA256', 'STATUSLIST_SHA256', 'PRESENTATION_SHA256']
72
+ if (validTypes.indexOf(parsed.type) === -1) {
73
+ return { valid: false, error: 'Invalid anchor type' }
74
+ }
75
+
76
+ if (!/^[a-fA-F0-9]{64}$/.test(parsed.hash)) {
77
+ return { valid: false, error: 'Invalid hash format' }
78
+ }
79
+
80
+ return {
81
+ valid: true,
82
+ protocol: parsed.protocol,
83
+ version: parsed.version,
84
+ type: parsed.type,
85
+ hash: parsed.hash,
86
+ issuer: parsed.issuer,
87
+ timestamp: parsed.timestamp
88
+ }
89
+ } catch (error) {
90
+ return {
91
+ valid: false,
92
+ error: 'Failed to parse anchor payload: ' + error.message
93
+ }
94
+ }
95
+ }
96
+
97
+ module.exports = {
98
+ sha256Hex: sha256Hex,
99
+ buildAnchorPayload: buildAnchorPayload,
100
+ verifyAnchorHash: verifyAnchorHash,
101
+ parseAnchorPayload: parseAnchorPayload
102
+ }
@@ -0,0 +1,177 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * DID:web Module
5
+ * Legally-recognizable DID (did:web) generation and management
6
+ * Supports ES256 (P-256) and ES256K (secp256k1) keys
7
+ */
8
+
9
+ var crypto = require('crypto')
10
+
11
+ // Generate issuer keys (ES256 or ES256K)
12
+ async function generateIssuerKeys(opts) {
13
+ opts = opts || {}
14
+ var alg = opts.alg || 'ES256'
15
+ var kid = opts.kid || 'key-' + Date.now()
16
+
17
+ if (alg !== 'ES256' && alg !== 'ES256K') {
18
+ throw new Error('Invalid algorithm. Must be ES256 or ES256K')
19
+ }
20
+
21
+ var keyPair
22
+ if (alg === 'ES256') {
23
+ // P-256 (NIST curve)
24
+ keyPair = crypto.generateKeyPairSync('ec', {
25
+ namedCurve: 'P-256',
26
+ publicKeyEncoding: { type: 'spki', format: 'pem' },
27
+ privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
28
+ })
29
+ } else {
30
+ // secp256k1
31
+ keyPair = crypto.generateKeyPairSync('ec', {
32
+ namedCurve: 'secp256k1',
33
+ publicKeyEncoding: { type: 'spki', format: 'pem' },
34
+ privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
35
+ })
36
+ }
37
+
38
+ // Convert to JWK format
39
+ var publicJwk = crypto.createPublicKey(keyPair.publicKey).export({ format: 'jwk' })
40
+ var privateJwk = crypto.createPrivateKey(keyPair.privateKey).export({ format: 'jwk' })
41
+
42
+ // Add required JWK fields
43
+ publicJwk.kid = kid
44
+ publicJwk.alg = alg
45
+ publicJwk.use = 'sig'
46
+ publicJwk.kty = 'EC'
47
+
48
+ privateJwk.kid = kid
49
+ privateJwk.alg = alg
50
+ privateJwk.use = 'sig'
51
+ privateJwk.kty = 'EC'
52
+
53
+ return {
54
+ privateJwk: privateJwk,
55
+ publicJwk: publicJwk,
56
+ kid: kid,
57
+ alg: alg
58
+ }
59
+ }
60
+
61
+ // Build did:web documents (did.json and jwks.json)
62
+ function buildDidWebDocuments(params) {
63
+ if (!params.domain) {
64
+ throw new Error('domain is required')
65
+ }
66
+
67
+ var domain = params.domain
68
+ var did = 'did:web:' + domain.replace(/:/g, '%3A')
69
+
70
+ var verificationMethods = []
71
+ var publicKeys = []
72
+
73
+ // Add P-256 key if provided
74
+ if (params.p256) {
75
+ var p256Method = {
76
+ id: did + '#' + params.p256.kid,
77
+ type: 'JsonWebKey2020',
78
+ controller: did,
79
+ publicKeyJwk: params.p256.jwk
80
+ }
81
+ verificationMethods.push(p256Method)
82
+ publicKeys.push(params.p256.jwk)
83
+ }
84
+
85
+ // Add secp256k1 key if provided
86
+ if (params.k1) {
87
+ var k1Method = {
88
+ id: did + '#' + params.k1.kid,
89
+ type: 'JsonWebKey2020',
90
+ controller: did,
91
+ publicKeyJwk: params.k1.jwk
92
+ }
93
+ verificationMethods.push(k1Method)
94
+ publicKeys.push(params.k1.jwk)
95
+ }
96
+
97
+ if (verificationMethods.length === 0) {
98
+ throw new Error('At least one key (p256 or k1) must be provided')
99
+ }
100
+
101
+ // Build DID Document
102
+ var didDocument = {
103
+ '@context': [
104
+ 'https://www.w3.org/ns/did/v1',
105
+ 'https://w3id.org/security/suites/jws-2020/v1'
106
+ ],
107
+ id: did,
108
+ verificationMethod: verificationMethods,
109
+ authentication: verificationMethods.map(function(vm) { return vm.id }),
110
+ assertionMethod: verificationMethods.map(function(vm) { return vm.id })
111
+ }
112
+
113
+ if (params.controllerName) {
114
+ didDocument.controller = params.controllerName
115
+ }
116
+
117
+ // Build JWKS
118
+ var jwks = {
119
+ keys: publicKeys
120
+ }
121
+
122
+ return {
123
+ did: did,
124
+ didDocument: didDocument,
125
+ jwks: jwks
126
+ }
127
+ }
128
+
129
+ // Rotate issuer key
130
+ function rotateIssuerKey(params) {
131
+ if (!params.domain || !params.newKey) {
132
+ throw new Error('domain and newKey are required')
133
+ }
134
+
135
+ var domain = params.domain
136
+ var did = 'did:web:' + domain.replace(/:/g, '%3A')
137
+ var keepOldForDays = params.keepOldForDays || 30
138
+
139
+ // Create verification method for new key
140
+ var newMethod = {
141
+ id: did + '#' + params.newKey.kid,
142
+ type: 'JsonWebKey2020',
143
+ controller: did,
144
+ publicKeyJwk: params.newKey.jwk
145
+ }
146
+
147
+ // Build updated DID Document with new key as primary
148
+ var didDocument = {
149
+ '@context': [
150
+ 'https://www.w3.org/ns/did/v1',
151
+ 'https://w3id.org/security/suites/jws-2020/v1'
152
+ ],
153
+ id: did,
154
+ verificationMethod: [newMethod],
155
+ authentication: [newMethod.id],
156
+ assertionMethod: [newMethod.id],
157
+ rotationInfo: {
158
+ rotatedAt: new Date().toISOString(),
159
+ gracePeriodDays: keepOldForDays
160
+ }
161
+ }
162
+
163
+ var jwks = {
164
+ keys: [params.newKey.jwk]
165
+ }
166
+
167
+ return {
168
+ didDocument: didDocument,
169
+ jwks: jwks
170
+ }
171
+ }
172
+
173
+ module.exports = {
174
+ generateIssuerKeys: generateIssuerKeys,
175
+ buildDidWebDocuments: buildDidWebDocuments,
176
+ rotateIssuerKey: rotateIssuerKey
177
+ }
@@ -0,0 +1,164 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * StatusList2021 Module
5
+ * W3C StatusList2021 for credential revocation and suspension
6
+ */
7
+
8
+ var vcjwt = require('../vcjwt')
9
+ var crypto = require('crypto')
10
+
11
+ // Create a new status list
12
+ async function createStatusList(params) {
13
+ if (!params.issuerDid || !params.privateJwk) {
14
+ throw new Error('issuerDid and privateJwk are required')
15
+ }
16
+
17
+ var listId = params.listId || params.issuerDid + '/status/' + Date.now()
18
+
19
+ // Create a bitstring for 100,000 credentials (default size)
20
+ var listSize = params.listSize || 100000
21
+ var byteSize = Math.ceil(listSize / 8)
22
+ var bitstringBuffer = Buffer.alloc(byteSize, 0)
23
+
24
+ // Compress with gzip
25
+ var zlib = require('zlib')
26
+ var compressed = zlib.gzipSync(bitstringBuffer)
27
+ var encodedCompressed = compressed.toString('base64')
28
+
29
+ // Create StatusList2021 credential
30
+ var statusListCredential = {
31
+ '@context': [
32
+ 'https://www.w3.org/2018/credentials/v1',
33
+ 'https://w3id.org/vc/status-list/2021/v1'
34
+ ],
35
+ type: ['VerifiableCredential', 'StatusList2021Credential'],
36
+ issuer: params.issuerDid,
37
+ issuanceDate: new Date().toISOString(),
38
+ credentialSubject: {
39
+ id: listId,
40
+ type: 'StatusList2021',
41
+ statusPurpose: 'revocation',
42
+ encodedList: encodedCompressed
43
+ }
44
+ }
45
+
46
+ // Issue as JWT
47
+ var result = await vcjwt.issueVcJwt({
48
+ issuerDid: params.issuerDid,
49
+ subjectId: listId,
50
+ types: ['VerifiableCredential', 'StatusList2021Credential'],
51
+ credentialSubject: statusListCredential.credentialSubject,
52
+ privateJwk: params.privateJwk,
53
+ alg: params.privateJwk.alg || 'ES256'
54
+ })
55
+
56
+ return {
57
+ listVcJwt: result.jwt,
58
+ listId: listId
59
+ }
60
+ }
61
+
62
+ // Update status list (revoke/suspend/activate)
63
+ async function updateStatusList(params) {
64
+ if (!params.listVcJwt || params.index === undefined || !params.status || !params.privateJwk) {
65
+ throw new Error('listVcJwt, index, status, and privateJwk are required')
66
+ }
67
+
68
+ // Decode the existing status list JWT
69
+ var parts = params.listVcJwt.split('.')
70
+ if (parts.length !== 3) {
71
+ throw new Error('Invalid JWT format')
72
+ }
73
+
74
+ var payload = JSON.parse(vcjwt.base64UrlDecode(parts[1]).toString())
75
+ var encodedList = payload.vc.credentialSubject.encodedList
76
+
77
+ // Decompress
78
+ var zlib = require('zlib')
79
+ var compressed = Buffer.from(encodedList, 'base64')
80
+ var bitstring = zlib.gunzipSync(compressed)
81
+
82
+ // Update the bit at the given index
83
+ var byteIndex = Math.floor(params.index / 8)
84
+ var bitIndex = params.index % 8
85
+
86
+ if (byteIndex >= bitstring.length) {
87
+ throw new Error('Index out of range')
88
+ }
89
+
90
+ // StatusList2021 uses 2 bits per credential for 4 states
91
+ // For simplicity, we'll use single bit: 0=valid, 1=revoked/suspended
92
+ var statusBit = (params.status === 'revoked' || params.status === 'suspended') ? 1 : 0
93
+
94
+ if (statusBit === 1) {
95
+ bitstring[byteIndex] |= (1 << bitIndex)
96
+ } else {
97
+ bitstring[byteIndex] &= ~(1 << bitIndex)
98
+ }
99
+
100
+ // Recompress
101
+ var recompressed = zlib.gzipSync(bitstring)
102
+ var newEncodedList = recompressed.toString('base64')
103
+
104
+ // Create updated credential
105
+ var updatedCredentialSubject = {
106
+ id: payload.vc.credentialSubject.id,
107
+ type: 'StatusList2021',
108
+ statusPurpose: 'revocation',
109
+ encodedList: newEncodedList
110
+ }
111
+
112
+ // Re-issue as JWT
113
+ var result = await vcjwt.issueVcJwt({
114
+ issuerDid: payload.iss,
115
+ subjectId: payload.vc.credentialSubject.id,
116
+ types: ['VerifiableCredential', 'StatusList2021Credential'],
117
+ credentialSubject: updatedCredentialSubject,
118
+ privateJwk: params.privateJwk,
119
+ alg: params.privateJwk.alg || 'ES256'
120
+ })
121
+
122
+ return {
123
+ listVcJwt: result.jwt
124
+ }
125
+ }
126
+
127
+ // Get credential status entry
128
+ function getCredentialStatusEntry(params) {
129
+ if (!params.listVcJwt || params.index === undefined) {
130
+ throw new Error('listVcJwt and index are required')
131
+ }
132
+
133
+ // Decode the status list JWT
134
+ var parts = params.listVcJwt.split('.')
135
+ if (parts.length !== 3) {
136
+ throw new Error('Invalid JWT format')
137
+ }
138
+
139
+ var payload = JSON.parse(vcjwt.base64UrlDecode(parts[1]).toString())
140
+ var encodedList = payload.vc.credentialSubject.encodedList
141
+
142
+ // Decompress
143
+ var zlib = require('zlib')
144
+ var compressed = Buffer.from(encodedList, 'base64')
145
+ var bitstring = zlib.gunzipSync(compressed)
146
+
147
+ // Check the bit at the given index
148
+ var byteIndex = Math.floor(params.index / 8)
149
+ var bitIndex = params.index % 8
150
+
151
+ if (byteIndex >= bitstring.length) {
152
+ throw new Error('Index out of range')
153
+ }
154
+
155
+ var bit = (bitstring[byteIndex] >> bitIndex) & 1
156
+
157
+ return bit === 1 ? 'revoked' : 'valid'
158
+ }
159
+
160
+ module.exports = {
161
+ createStatusList: createStatusList,
162
+ updateStatusList: updateStatusList,
163
+ getCredentialStatusEntry: getCredentialStatusEntry
164
+ }