smartledger-bsv 3.2.2 → 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.
- package/CHANGELOG.md +147 -0
- package/architecture_demo.js +247 -0
- package/bsv-gdaf.min.js +37 -0
- package/bsv-ltp.min.js +37 -0
- package/bsv-shamir.min.js +12 -0
- package/bsv.bundle.js +9 -9
- package/build/bsv-smartcontract.min.js +10 -8
- package/build/bsv.bundle.js +9 -9
- package/build/bsv.min.js +10 -8
- package/build/webpack.gdaf.config.js +54 -0
- package/build/webpack.ltp.config.js +17 -0
- package/bundle-entry.js +77 -1
- package/complete_ltp_demo.js +511 -0
- package/gdaf-entry.js +54 -0
- package/index.js +259 -0
- package/lib/crypto/shamir.js +360 -0
- package/lib/gdaf/attestation-signer.js +461 -0
- package/lib/gdaf/attestation-verifier.js +600 -0
- package/lib/gdaf/did-resolver.js +382 -0
- package/lib/gdaf/index.js +471 -0
- package/lib/gdaf/schema-validator.js +682 -0
- package/lib/gdaf/smartledger-anchor.js +486 -0
- package/lib/gdaf/zk-prover.js +507 -0
- package/lib/ltp/anchor.js +438 -0
- package/lib/ltp/claim.js +1026 -0
- package/lib/ltp/index.js +470 -0
- package/lib/ltp/obligation.js +945 -0
- package/lib/ltp/proof.js +828 -0
- package/lib/ltp/registry.js +702 -0
- package/lib/ltp/right.js +765 -0
- package/lib/smart_contract/API_REFERENCE.md +1 -1
- package/lib/smart_contract/EXAMPLES.md +2 -2
- package/lib/smart_contract/QUICK_START.md +2 -2
- package/lib/smart_contract/README.md +1 -1
- package/ltp-entry.js +92 -0
- package/package.json +44 -4
- package/shamir-entry.js +173 -0
- package/shamir_demo.js +121 -0
- package/simple_demo.js +204 -0
- package/test_shamir.js +221 -0
- package/test_standalone_shamir.html +83 -0
package/gdaf-entry.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GDAF (Global Digital Attestation Framework) Standalone Bundle
|
|
5
|
+
*
|
|
6
|
+
* Entry point for creating standalone distribution of the Global Digital
|
|
7
|
+
* Attestation Framework. This module can be built with webpack to create
|
|
8
|
+
* a standalone bundle for browser use.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Core BSV dependencies for GDAF
|
|
12
|
+
var PublicKey = require('./lib/publickey')
|
|
13
|
+
var PrivateKey = require('./lib/privatekey')
|
|
14
|
+
var Address = require('./lib/address')
|
|
15
|
+
var Transaction = require('./lib/transaction')
|
|
16
|
+
var Script = require('./lib/script')
|
|
17
|
+
var Hash = require('./lib/crypto/hash')
|
|
18
|
+
var ECDSA = require('./lib/crypto/ecdsa')
|
|
19
|
+
var Signature = require('./lib/crypto/signature')
|
|
20
|
+
|
|
21
|
+
// GDAF modules
|
|
22
|
+
var GDAF = require('./lib/gdaf')
|
|
23
|
+
|
|
24
|
+
// Create minimal BSV context for GDAF
|
|
25
|
+
var bsvContext = {
|
|
26
|
+
PublicKey: PublicKey,
|
|
27
|
+
PrivateKey: PrivateKey,
|
|
28
|
+
Address: Address,
|
|
29
|
+
Transaction: Transaction,
|
|
30
|
+
Script: Script,
|
|
31
|
+
crypto: {
|
|
32
|
+
Hash: Hash,
|
|
33
|
+
ECDSA: ECDSA,
|
|
34
|
+
Signature: Signature
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Export GDAF with BSV context
|
|
39
|
+
module.exports = {
|
|
40
|
+
GDAF: GDAF,
|
|
41
|
+
bsv: bsvContext,
|
|
42
|
+
|
|
43
|
+
// Direct access to GDAF classes for convenience
|
|
44
|
+
DIDResolver: require('./lib/gdaf/did-resolver'),
|
|
45
|
+
AttestationSigner: require('./lib/gdaf/attestation-signer'),
|
|
46
|
+
AttestationVerifier: require('./lib/gdaf/attestation-verifier'),
|
|
47
|
+
ZKProver: require('./lib/gdaf/zk-prover'),
|
|
48
|
+
SmartLedgerAnchor: require('./lib/gdaf/smartledger-anchor'),
|
|
49
|
+
SchemaValidator: require('./lib/gdaf/schema-validator'),
|
|
50
|
+
|
|
51
|
+
// Utility functions
|
|
52
|
+
version: '1.0.0',
|
|
53
|
+
description: 'SmartLedger BSV Global Digital Attestation Framework'
|
|
54
|
+
}
|
package/index.js
CHANGED
|
@@ -48,6 +48,7 @@ bsv.crypto.Hash = require('./lib/crypto/hash')
|
|
|
48
48
|
bsv.crypto.Random = require('./lib/crypto/random')
|
|
49
49
|
bsv.crypto.Point = require('./lib/crypto/point')
|
|
50
50
|
bsv.crypto.Signature = require('./lib/crypto/signature')
|
|
51
|
+
bsv.crypto.Shamir = require('./lib/crypto/shamir')
|
|
51
52
|
|
|
52
53
|
// SmartLedger security enhancements
|
|
53
54
|
bsv.crypto.SmartVerify = require('./lib/crypto/smartledger_verify')
|
|
@@ -82,8 +83,14 @@ bsv.PrivateKey = require('./lib/privatekey')
|
|
|
82
83
|
bsv.PublicKey = require('./lib/publickey')
|
|
83
84
|
bsv.Script = require('./lib/script')
|
|
84
85
|
bsv.Transaction = require('./lib/transaction')
|
|
86
|
+
bsv.Input = require('./lib/transaction').Input
|
|
87
|
+
bsv.Output = require('./lib/transaction').Output
|
|
88
|
+
bsv.UnspentOutput = require('./lib/transaction').UnspentOutput
|
|
85
89
|
bsv.Message = require('./lib/message')
|
|
90
|
+
bsv.Mnemonic = require('./lib/mnemonic')
|
|
91
|
+
bsv.ECIES = require('./lib/ecies')
|
|
86
92
|
bsv.Signature = require('./lib/crypto/signature')
|
|
93
|
+
bsv.Shamir = require('./lib/crypto/shamir')
|
|
87
94
|
|
|
88
95
|
// SmartLedger security modules (top-level access)
|
|
89
96
|
bsv.SmartLedger = {
|
|
@@ -119,5 +126,257 @@ if (typeof window === 'undefined' && typeof require === 'function') {
|
|
|
119
126
|
}
|
|
120
127
|
}
|
|
121
128
|
|
|
129
|
+
// Global Digital Attestation Framework (GDAF)
|
|
130
|
+
bsv.GDAF = require('./lib/gdaf')
|
|
131
|
+
|
|
132
|
+
// GDAF Direct Access Methods (for easier developer experience)
|
|
133
|
+
bsv.createDID = function(publicKey) {
|
|
134
|
+
var gdaf = new bsv.GDAF()
|
|
135
|
+
return gdaf.createDID(publicKey)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
bsv.resolveDID = function(did) {
|
|
139
|
+
var gdaf = new bsv.GDAF()
|
|
140
|
+
return gdaf.resolveDID(did)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
bsv.createEmailCredential = function(issuerDID, subjectDID, email, issuerPrivateKey) {
|
|
144
|
+
var gdaf = new bsv.GDAF()
|
|
145
|
+
return gdaf.createEmailCredential(issuerDID, subjectDID, email, issuerPrivateKey)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
bsv.createAgeCredential = function(issuerDID, subjectDID, ageThreshold, birthDate, issuerPrivateKey) {
|
|
149
|
+
var gdaf = new bsv.GDAF()
|
|
150
|
+
return gdaf.createAgeCredential(issuerDID, subjectDID, ageThreshold, birthDate, issuerPrivateKey)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
bsv.createKYCCredential = function(issuerDID, subjectDID, level, piiHashes, issuerPrivateKey) {
|
|
154
|
+
var gdaf = new bsv.GDAF()
|
|
155
|
+
return gdaf.createKYCCredential(issuerDID, subjectDID, level, piiHashes, issuerPrivateKey)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
bsv.verifyCredential = function(credential, options) {
|
|
159
|
+
var gdaf = new bsv.GDAF()
|
|
160
|
+
return gdaf.verifyCredential(credential, options)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
bsv.validateCredential = function(credential, schema) {
|
|
164
|
+
var gdaf = new bsv.GDAF()
|
|
165
|
+
return gdaf.validateCredential(credential, schema)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
bsv.generateSelectiveProof = function(credential, revealedFields, nonce) {
|
|
169
|
+
var gdaf = new bsv.GDAF()
|
|
170
|
+
return gdaf.generateSelectiveProof(credential, revealedFields, nonce)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
bsv.generateAgeProof = function(ageCredential, minimumAge, nonce) {
|
|
174
|
+
var gdaf = new bsv.GDAF()
|
|
175
|
+
return gdaf.generateAgeProof(ageCredential, minimumAge, nonce)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
bsv.verifyAgeProof = function(proof, minimumAge, issuerDID) {
|
|
179
|
+
var gdaf = new bsv.GDAF()
|
|
180
|
+
return gdaf.verifyAgeProof(proof, minimumAge, issuerDID)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
bsv.createPresentation = function(credentials, holderDID, holderPrivateKey, options) {
|
|
184
|
+
var gdaf = new bsv.GDAF()
|
|
185
|
+
return gdaf.createPresentation(credentials, holderDID, holderPrivateKey, options)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
bsv.getCredentialSchemas = function() {
|
|
189
|
+
var gdaf = new bsv.GDAF()
|
|
190
|
+
return gdaf.getAllSchemas()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
bsv.createCredentialTemplate = function(credentialType) {
|
|
194
|
+
var gdaf = new bsv.GDAF()
|
|
195
|
+
return gdaf.createTemplate(credentialType)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Legal Token Protocol (LTP) - Primitives-Only Interface
|
|
199
|
+
bsv.LTP = require('./lib/ltp')
|
|
200
|
+
|
|
201
|
+
// LTP Right Token Primitives
|
|
202
|
+
bsv.prepareRightToken = function(type, issuerDID, subjectDID, claim, issuerPrivateKey, options) {
|
|
203
|
+
return bsv.LTP.Right.prepareRightToken(type, issuerDID, subjectDID, claim, issuerPrivateKey, options)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
bsv.prepareRightTokenVerification = function(token, options) {
|
|
207
|
+
return bsv.LTP.Right.prepareRightTokenVerification(token, options)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
bsv.prepareRightTokenTransfer = function(token, newOwnerDID, currentOwnerKey, options) {
|
|
211
|
+
return bsv.LTP.Right.prepareRightTokenTransfer(token, newOwnerDID, currentOwnerKey, options)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
bsv.prepareRightTypeValidation = function(type) {
|
|
215
|
+
return bsv.LTP.Right.prepareRightTypeValidation(type)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// LTP Obligation Token Primitives
|
|
219
|
+
bsv.prepareObligationToken = function(type, issuerDID, obligorDID, obligation, issuerPrivateKey, options) {
|
|
220
|
+
return bsv.LTP.Obligation.prepareObligationToken(type, issuerDID, obligorDID, obligation, issuerPrivateKey, options)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
bsv.prepareObligationVerification = function(token, options) {
|
|
224
|
+
return bsv.LTP.Obligation.prepareObligationVerification(token, options)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
bsv.prepareObligationFulfillment = function(token, fulfillment, obligorKey, options) {
|
|
228
|
+
return bsv.LTP.Obligation.prepareObligationFulfillment(token, fulfillment, obligorKey, options)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
bsv.prepareObligationBreachAssessment = function(token, breach, assessor) {
|
|
232
|
+
return bsv.LTP.Obligation.prepareObligationBreachAssessment(token, breach, assessor)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
bsv.prepareObligationMonitoringReport = function(obligations, criteria) {
|
|
236
|
+
return bsv.LTP.Obligation.prepareObligationMonitoringReport(obligations, criteria)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// LTP Claim Validation Primitives
|
|
240
|
+
bsv.prepareClaimValidation = function(claim, schemaName) {
|
|
241
|
+
return bsv.LTP.Claim.prepareClaimValidation(claim, schemaName)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
bsv.prepareClaimAttestation = function(claim, schemaName, attestor) {
|
|
245
|
+
return bsv.LTP.Claim.prepareClaimAttestation(claim, schemaName, attestor)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
bsv.prepareClaimDispute = function(claimHash, disputant, dispute) {
|
|
249
|
+
return bsv.LTP.Claim.prepareClaimDispute(claimHash, disputant, dispute)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
bsv.prepareBulkClaimValidation = function(claims, schemaName) {
|
|
253
|
+
return bsv.LTP.Claim.prepareBulkClaimValidation(claims, schemaName)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
bsv.prepareClaimTemplate = function(schemaName, options) {
|
|
257
|
+
return bsv.LTP.Claim.prepareClaimTemplate(schemaName, options)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// LTP Proof Generation Primitives
|
|
261
|
+
bsv.prepareSignatureProof = function(token, privateKey, options) {
|
|
262
|
+
return bsv.LTP.Proof.prepareSignatureProof(token, privateKey, options)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
bsv.prepareSignatureVerification = function(token, publicKey) {
|
|
266
|
+
return bsv.LTP.Proof.prepareSignatureVerification(token, publicKey)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
bsv.prepareSelectiveDisclosure = function(token, revealedFields, nonce) {
|
|
270
|
+
return bsv.LTP.Proof.prepareSelectiveDisclosure(token, revealedFields, nonce)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
bsv.prepareSelectiveDisclosureVerification = function(proof, expectedNonce) {
|
|
274
|
+
return bsv.LTP.Proof.prepareSelectiveDisclosureVerification(proof, expectedNonce)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
bsv.prepareLegalValidityProof = function(token, jurisdiction, nonce) {
|
|
278
|
+
return bsv.LTP.Proof.prepareLegalValidityProof(token, jurisdiction, nonce)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
bsv.prepareZeroKnowledgeProof = function(token, statement, nonce) {
|
|
282
|
+
return bsv.LTP.Proof.prepareZeroKnowledgeProof(token, statement, nonce)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// LTP Registry Management Primitives
|
|
286
|
+
bsv.prepareRegistry = function(config) {
|
|
287
|
+
return bsv.LTP.Registry.prepareRegistry(config)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
bsv.prepareTokenRegistration = function(token, registryConfig, options) {
|
|
291
|
+
return bsv.LTP.Registry.prepareTokenRegistration(token, registryConfig, options)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
bsv.prepareTokenApproval = function(tokenId, approver, registryConfig) {
|
|
295
|
+
return bsv.LTP.Registry.prepareTokenApproval(tokenId, approver, registryConfig)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
bsv.prepareTokenRevocation = function(tokenId, revocation, registryConfig) {
|
|
299
|
+
return bsv.LTP.Registry.prepareTokenRevocation(tokenId, revocation, registryConfig)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
bsv.prepareTokenStatusQuery = function(tokenId, registryConfig) {
|
|
303
|
+
return bsv.LTP.Registry.prepareTokenStatusQuery(tokenId, registryConfig)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
bsv.prepareTokenSearch = function(criteria, registryConfig) {
|
|
307
|
+
return bsv.LTP.Registry.prepareTokenSearch(criteria, registryConfig)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
bsv.prepareStatisticsQuery = function(registryConfig) {
|
|
311
|
+
return bsv.LTP.Registry.prepareStatisticsQuery(registryConfig)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
bsv.prepareAuditLogQuery = function(registryConfig, options) {
|
|
315
|
+
return bsv.LTP.Registry.prepareAuditLogQuery(registryConfig, options)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// LTP Blockchain Anchoring Primitives
|
|
319
|
+
bsv.prepareTokenCommitment = function(token, options) {
|
|
320
|
+
return bsv.LTP.Anchor.prepareTokenCommitment(token, options)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
bsv.prepareBatchCommitment = function(tokens, options) {
|
|
324
|
+
return bsv.LTP.Anchor.prepareBatchCommitment(tokens, options)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
bsv.verifyTokenAnchor = function(token, txid, txData) {
|
|
328
|
+
return bsv.LTP.Anchor.verifyTokenAnchor(token, txid, txData)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
bsv.formatRevocation = function(tokenId, revocationData) {
|
|
332
|
+
return bsv.LTP.Anchor.formatRevocation(tokenId, revocationData)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// LTP Static Data Access (unchanged)
|
|
336
|
+
bsv.getRightTypes = function() {
|
|
337
|
+
return bsv.LTP.Right.getRightTypes()
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
bsv.getObligationTypes = function() {
|
|
341
|
+
return bsv.LTP.Obligation.getObligationTypes()
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
bsv.getObligationPriority = function() {
|
|
345
|
+
return bsv.LTP.Obligation.getObligationPriority()
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
bsv.getObligationStatus = function() {
|
|
349
|
+
return bsv.LTP.Obligation.getObligationStatus()
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
bsv.getClaimSchemas = function() {
|
|
353
|
+
return bsv.LTP.Claim.getSchemas()
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
bsv.getClaimSchemaNames = function() {
|
|
357
|
+
return bsv.LTP.Claim.getSchemaNames()
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
bsv.getClaimSchema = function(schemaName) {
|
|
361
|
+
return bsv.LTP.Claim.getSchema(schemaName)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
bsv.createClaimTemplate = function(schemaName) {
|
|
365
|
+
return bsv.LTP.Claim.createTemplate(schemaName)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// LTP Utility Functions
|
|
369
|
+
bsv.canonicalizeClaim = function(claim) {
|
|
370
|
+
return bsv.LTP.Claim.canonicalize(claim)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
bsv.hashClaim = function(claim) {
|
|
374
|
+
return bsv.LTP.Claim.hash(claim)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
bsv.addCustomClaimSchema = function(name, schema) {
|
|
378
|
+
return bsv.LTP.Claim.addSchema(name, schema)
|
|
379
|
+
}
|
|
380
|
+
|
|
122
381
|
// Internal usage, exposed for testing/advanced tweaking
|
|
123
382
|
bsv.Transaction.sighash = require('./lib/transaction/sighash')
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
var BN = require('./bn')
|
|
4
|
+
var Random = require('./random')
|
|
5
|
+
var Hash = require('./hash')
|
|
6
|
+
var _ = require('../util/_')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Shamir Secret Sharing implementation for secure secret distribution
|
|
10
|
+
* Based on Shamir's Secret Sharing algorithm using finite field arithmetic
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Split secrets into N shares with K threshold
|
|
14
|
+
* - Reconstruct secret from any K shares
|
|
15
|
+
* - Cryptographically secure random polynomial generation
|
|
16
|
+
* - Support for arbitrary secret sizes via byte-level processing
|
|
17
|
+
* - Compatible with BSV cryptographic primitives
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Prime number for finite field operations
|
|
22
|
+
* Using a large prime that's suitable for byte operations (2^31 - 1)
|
|
23
|
+
*/
|
|
24
|
+
var PRIME = new BN(2147483647) // Mersenne prime 2^31 - 1
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Shamir Secret Sharing constructor
|
|
28
|
+
* @param {Object} options - Configuration options
|
|
29
|
+
*/
|
|
30
|
+
function Shamir(options) {
|
|
31
|
+
if (!(this instanceof Shamir)) {
|
|
32
|
+
return new Shamir(options)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.options = options || {}
|
|
36
|
+
return this
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Split a secret into shares using Shamir's Secret Sharing
|
|
41
|
+
* @param {Buffer|String} secret - The secret to split
|
|
42
|
+
* @param {Number} threshold - Minimum number of shares needed to reconstruct
|
|
43
|
+
* @param {Number} shares - Total number of shares to generate
|
|
44
|
+
* @param {Object} options - Additional options
|
|
45
|
+
* @returns {Array} Array of share objects with {x, y} coordinates
|
|
46
|
+
*/
|
|
47
|
+
Shamir.split = function(secret, threshold, shares, options) {
|
|
48
|
+
options = options || {}
|
|
49
|
+
|
|
50
|
+
if (!secret) {
|
|
51
|
+
throw new Error('Secret is required')
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (threshold < 2) {
|
|
55
|
+
throw new Error('Threshold must be at least 2')
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (shares < threshold) {
|
|
59
|
+
throw new Error('Number of shares must be at least threshold')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (threshold > 255 || shares > 255) {
|
|
63
|
+
throw new Error('Threshold and shares must be <= 255')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Convert secret to buffer if string
|
|
67
|
+
var secretBuffer = Buffer.isBuffer(secret) ? secret : Buffer.from(secret, 'utf8')
|
|
68
|
+
|
|
69
|
+
// Process each byte of the secret
|
|
70
|
+
var allShares = []
|
|
71
|
+
|
|
72
|
+
for (var i = 0; i < secretBuffer.length; i++) {
|
|
73
|
+
var byte = secretBuffer[i]
|
|
74
|
+
var byteShares = Shamir._splitByte(byte, threshold, shares)
|
|
75
|
+
allShares.push(byteShares)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Combine shares across bytes
|
|
79
|
+
var result = []
|
|
80
|
+
for (var j = 0; j < shares; j++) {
|
|
81
|
+
var shareData = {
|
|
82
|
+
id: j + 1,
|
|
83
|
+
threshold: threshold,
|
|
84
|
+
shares: shares,
|
|
85
|
+
length: secretBuffer.length,
|
|
86
|
+
bytes: []
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (var k = 0; k < allShares.length; k++) {
|
|
90
|
+
shareData.bytes.push(allShares[k][j])
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
result.push(shareData)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Combine shares to reconstruct the original secret
|
|
101
|
+
* @param {Array} shares - Array of share objects
|
|
102
|
+
* @returns {Buffer} The reconstructed secret
|
|
103
|
+
*/
|
|
104
|
+
Shamir.combine = function(shares) {
|
|
105
|
+
if (!shares || shares.length === 0) {
|
|
106
|
+
throw new Error('Shares array is required')
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Validate shares
|
|
110
|
+
var threshold = shares[0].threshold
|
|
111
|
+
var totalShares = shares[0].shares
|
|
112
|
+
var secretLength = shares[0].length
|
|
113
|
+
|
|
114
|
+
if (shares.length < threshold) {
|
|
115
|
+
throw new Error('Insufficient shares: need ' + threshold + ', got ' + shares.length)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Verify all shares have same parameters
|
|
119
|
+
for (var i = 0; i < shares.length; i++) {
|
|
120
|
+
if (shares[i].threshold !== threshold || shares[i].shares !== totalShares) {
|
|
121
|
+
throw new Error('Shares have inconsistent parameters')
|
|
122
|
+
}
|
|
123
|
+
if (shares[i].length !== secretLength) {
|
|
124
|
+
throw new Error('Shares have different secret lengths')
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var reconstructedBytes = []
|
|
129
|
+
|
|
130
|
+
// Reconstruct each byte
|
|
131
|
+
for (var j = 0; j < secretLength; j++) {
|
|
132
|
+
var byteShares = []
|
|
133
|
+
for (var k = 0; k < Math.min(shares.length, threshold); k++) {
|
|
134
|
+
byteShares.push(shares[k].bytes[j])
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var byte = Shamir._combineByte(byteShares)
|
|
138
|
+
reconstructedBytes.push(byte)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Create buffer from reconstructed bytes
|
|
142
|
+
return Buffer.from(reconstructedBytes)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Split a single byte using polynomial interpolation
|
|
147
|
+
* @private
|
|
148
|
+
*/
|
|
149
|
+
Shamir._splitByte = function(secretByte, threshold, shares) {
|
|
150
|
+
// Convert byte to big number
|
|
151
|
+
var secret = new BN(secretByte)
|
|
152
|
+
|
|
153
|
+
// Generate random polynomial coefficients
|
|
154
|
+
var coefficients = [secret] // a0 = secret
|
|
155
|
+
|
|
156
|
+
for (var i = 1; i < threshold; i++) {
|
|
157
|
+
var coeff = Shamir._randomFieldElement()
|
|
158
|
+
coefficients.push(coeff)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Generate shares by evaluating polynomial at different points
|
|
162
|
+
var result = []
|
|
163
|
+
for (var x = 1; x <= shares; x++) {
|
|
164
|
+
var y = Shamir._evaluatePolynomial(coefficients, new BN(x))
|
|
165
|
+
result.push({
|
|
166
|
+
x: x,
|
|
167
|
+
y: y.toString(16)
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return result
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Combine shares for a single byte using Lagrange interpolation
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
Shamir._combineByte = function(shares) {
|
|
179
|
+
if (shares.length === 0) {
|
|
180
|
+
throw new Error('No shares provided')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
var result = new BN(0)
|
|
184
|
+
|
|
185
|
+
for (var i = 0; i < shares.length; i++) {
|
|
186
|
+
var xi = new BN(shares[i].x)
|
|
187
|
+
var yi = new BN(shares[i].y, 16)
|
|
188
|
+
|
|
189
|
+
// Calculate Lagrange basis polynomial
|
|
190
|
+
var numerator = new BN(1)
|
|
191
|
+
var denominator = new BN(1)
|
|
192
|
+
|
|
193
|
+
for (var j = 0; j < shares.length; j++) {
|
|
194
|
+
if (i !== j) {
|
|
195
|
+
var xj = new BN(shares[j].x)
|
|
196
|
+
// For Lagrange interpolation at x=0 (to get the constant term)
|
|
197
|
+
var numFactor = new BN(0).sub(xj)
|
|
198
|
+
if (numFactor.lt(new BN(0))) {
|
|
199
|
+
numFactor = numFactor.add(PRIME)
|
|
200
|
+
}
|
|
201
|
+
numerator = numerator.mul(numFactor).mod(PRIME)
|
|
202
|
+
|
|
203
|
+
var denFactor = xi.sub(xj)
|
|
204
|
+
if (denFactor.lt(new BN(0))) {
|
|
205
|
+
denFactor = denFactor.add(PRIME)
|
|
206
|
+
}
|
|
207
|
+
denominator = denominator.mul(denFactor).mod(PRIME)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Calculate modular inverse of denominator
|
|
212
|
+
var inverse = Shamir._modInverse(denominator, PRIME)
|
|
213
|
+
var lagrange = numerator.mul(inverse).mod(PRIME)
|
|
214
|
+
|
|
215
|
+
// Add to result
|
|
216
|
+
result = result.add(yi.mul(lagrange)).mod(PRIME)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Convert back to byte (0-255) - ensure positive result
|
|
220
|
+
var finalResult = result.mod(PRIME).mod(new BN(256))
|
|
221
|
+
return finalResult.toNumber()
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Evaluate polynomial at given point
|
|
226
|
+
* @private
|
|
227
|
+
*/
|
|
228
|
+
Shamir._evaluatePolynomial = function(coefficients, x) {
|
|
229
|
+
var result = new BN(0)
|
|
230
|
+
var xPower = new BN(1)
|
|
231
|
+
|
|
232
|
+
for (var i = 0; i < coefficients.length; i++) {
|
|
233
|
+
result = result.add(coefficients[i].mul(xPower)).mod(PRIME)
|
|
234
|
+
xPower = xPower.mul(x).mod(PRIME)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return result
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Generate random field element
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
Shamir._randomFieldElement = function() {
|
|
245
|
+
var bytes = Random.getRandomBuffer(32)
|
|
246
|
+
var num = new BN(bytes)
|
|
247
|
+
return num.mod(PRIME.sub(new BN(1))).add(new BN(1))
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Calculate modular inverse using extended Euclidean algorithm
|
|
252
|
+
* @private
|
|
253
|
+
*/
|
|
254
|
+
Shamir._modInverse = function(a, m) {
|
|
255
|
+
if (a.lt(new BN(0))) {
|
|
256
|
+
a = a.mod(m).add(m)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
var g = Shamir._extendedGCD(a, m)
|
|
260
|
+
|
|
261
|
+
if (!g.gcd.eq(new BN(1))) {
|
|
262
|
+
throw new Error('Modular inverse does not exist')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return g.x.mod(m).add(m).mod(m)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Extended Euclidean algorithm
|
|
270
|
+
* @private
|
|
271
|
+
*/
|
|
272
|
+
Shamir._extendedGCD = function(a, b) {
|
|
273
|
+
if (a.eq(new BN(0))) {
|
|
274
|
+
return { gcd: b, x: new BN(0), y: new BN(1) }
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
var g = Shamir._extendedGCD(b.mod(a), a)
|
|
278
|
+
|
|
279
|
+
return {
|
|
280
|
+
gcd: g.gcd,
|
|
281
|
+
x: g.y.sub(b.div(a).mul(g.x)),
|
|
282
|
+
y: g.x
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Verify share integrity
|
|
288
|
+
* @param {Object} share - Share to verify
|
|
289
|
+
* @returns {Boolean} True if share is valid
|
|
290
|
+
*/
|
|
291
|
+
Shamir.verifyShare = function(share) {
|
|
292
|
+
try {
|
|
293
|
+
if (!share || typeof share !== 'object') {
|
|
294
|
+
return false
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (!share.id || !share.threshold || !share.shares || !share.bytes || typeof share.length !== 'number') {
|
|
298
|
+
return false
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (share.threshold < 2 || share.shares < share.threshold) {
|
|
302
|
+
return false
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (!Array.isArray(share.bytes) || share.bytes.length !== share.length) {
|
|
306
|
+
return false
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Verify each byte share
|
|
310
|
+
for (var i = 0; i < share.bytes.length; i++) {
|
|
311
|
+
var byteShare = share.bytes[i]
|
|
312
|
+
if (!byteShare.x || !byteShare.y) {
|
|
313
|
+
return false
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (byteShare.x < 1 || byteShare.x > share.shares) {
|
|
317
|
+
return false
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Verify y is valid hex
|
|
321
|
+
try {
|
|
322
|
+
var testHex = byteShare.y
|
|
323
|
+
if (!/^[0-9a-fA-F]+$/.test(testHex)) {
|
|
324
|
+
return false
|
|
325
|
+
}
|
|
326
|
+
new BN(testHex, 16)
|
|
327
|
+
} catch (e) {
|
|
328
|
+
return false
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return true
|
|
333
|
+
} catch (e) {
|
|
334
|
+
return false
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Generate test vectors for validation
|
|
340
|
+
* @returns {Object} Test data
|
|
341
|
+
*/
|
|
342
|
+
Shamir.generateTestVectors = function() {
|
|
343
|
+
var secret = 'Hello, Bitcoin SV!'
|
|
344
|
+
var threshold = 3
|
|
345
|
+
var shares = 5
|
|
346
|
+
|
|
347
|
+
var splitShares = Shamir.split(secret, threshold, shares)
|
|
348
|
+
var reconstructed = Shamir.combine(splitShares.slice(0, threshold))
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
secret: secret,
|
|
352
|
+
threshold: threshold,
|
|
353
|
+
totalShares: shares,
|
|
354
|
+
shares: splitShares,
|
|
355
|
+
reconstructed: reconstructed.toString('utf8'),
|
|
356
|
+
valid: reconstructed.toString('utf8') === secret
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
module.exports = Shamir
|