@smartledger/bsv 7.12.0 → 8.0.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +38 -38
  3. package/bsv-didweb.min.js +6 -6
  4. package/bsv-gdaf.min.js +66 -66
  5. package/bsv-ltp.min.js +46 -46
  6. package/bsv-mnemonic.min.js +8 -8
  7. package/bsv-smartcontract.min.js +1 -1
  8. package/bsv.bundle.js +66 -66
  9. package/bsv.min.js +66 -66
  10. package/docs/AUDIT_SCOPE.md +29 -21
  11. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  12. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  13. package/docs/getting-started/INSTALLATION.md +23 -23
  14. package/docs/getting-started/QUICK_START.md +7 -7
  15. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  16. package/index.js +10 -2
  17. package/lib/crypto/bn.js +22 -2
  18. package/lib/crypto/hash.browser.js +13 -5
  19. package/lib/crypto/hash.js +58 -2
  20. package/lib/crypto/random.js +72 -15
  21. package/lib/didweb/index.js +88 -9
  22. package/lib/encoding/base58.js +67 -3
  23. package/lib/mnemonic/mnemonic.js +19 -5
  24. package/lib/mnemonic/pbkdf2.js +35 -2
  25. package/lib/script/interpreter.js +420 -58
  26. package/lib/transaction/input/multisig.js +1 -1
  27. package/lib/transaction/input/multisigscripthash.js +1 -1
  28. package/lib/transaction/input/publickey.js +1 -1
  29. package/lib/transaction/input/publickeyhash.js +1 -1
  30. package/lib/transaction/sighash.js +18 -6
  31. package/lib/transaction/signature.js +1 -1
  32. package/lib/util/inherits.js +37 -0
  33. package/package.json +7 -8
  34. package/test/consensus/base58-vectors.js +120 -0
  35. package/test/consensus/sv-script-vectors.js +81 -0
  36. package/test/consensus/sv-sighash-vectors.js +51 -0
  37. package/test/consensus/sv-tx-vectors.js +48 -0
  38. package/test/crypto/backend_selection.js +126 -0
  39. package/test/crypto/random.js +73 -0
  40. package/test/data/bitcoin-sv/README.md +170 -0
  41. package/test/data/bitcoin-sv/base58_encode_decode.json +14 -0
  42. package/test/data/bitcoin-sv/base58_keys_invalid.json +152 -0
  43. package/test/data/bitcoin-sv/base58_keys_valid.json +452 -0
  44. package/test/data/bitcoin-sv/script_tests.json +2591 -0
  45. package/test/data/bitcoin-sv/sighash.json +1003 -0
  46. package/test/data/bitcoin-sv/tx_invalid.json +285 -0
  47. package/test/data/bitcoin-sv/tx_valid.json +367 -0
  48. package/test/didweb/relationships.js +144 -0
  49. package/test/regressions.js +35 -0
  50. package/test/script/chronicle.js +170 -25
  51. package/test/script/defaults.js +93 -0
  52. package/test/script/genesis_limits.js +62 -6
  53. package/test/script/interpreter.js +24 -8
  54. package/test/transaction/sighash.js +21 -1
  55. package/test/transaction/unspentoutput.js +6 -1
  56. package/version.js +1 -1
@@ -1,37 +1,94 @@
1
1
  'use strict'
2
2
 
3
+ // WebCrypto refuses more than 65,536 bytes in a single getRandomValues() call, so large
4
+ // requests are filled in chunks. Node's randomBytes has no such limit, which is why this
5
+ // only matters on the WebCrypto path.
6
+ var MAX_GET_RANDOM_VALUES = 65536
7
+
3
8
  function Random () {
4
9
  }
5
10
 
6
- /* secure random bytes that sometimes throws an error due to lack of entropy */
11
+ /**
12
+ * Cryptographically secure random bytes.
13
+ *
14
+ * Backend selection is by FEATURE DETECTION, not by environment guess. This previously
15
+ * branched on `process.browser` — a Browserify-era convention that is undefined in React
16
+ * Native, Deno, Cloudflare Workers, Bun, and any bundler that does not shim it. All of
17
+ * those fell through to `require('crypto').randomBytes`. In React Native that is a hard
18
+ * failure at best; at worst a partial crypto shim (rn-nodeify and several RN starter
19
+ * templates register one) supplies a weak `randomBytes`, and `PrivateKey.fromRandom()`
20
+ * silently produces guessable keys.
21
+ *
22
+ * `globalThis.crypto.getRandomValues` covers browsers, Node >= 19, Deno, Workers, Bun,
23
+ * and React Native with react-native-get-random-values, so it is tried first.
24
+ *
25
+ * If no CSPRNG can be found this THROWS. That is as important as the detection: a key
26
+ * library must never return bytes it cannot vouch for.
27
+ *
28
+ * @param {number} size - number of bytes
29
+ * @returns {Buffer}
30
+ */
7
31
  Random.getRandomBuffer = function (size) {
8
- if (process.browser) { return Random.getRandomBufferBrowser(size) } else { return Random.getRandomBufferNode(size) }
32
+ var webcrypto = typeof globalThis !== 'undefined' ? globalThis.crypto : undefined
33
+ if (webcrypto && typeof webcrypto.getRandomValues === 'function') {
34
+ return Random._fromGetRandomValues(webcrypto, size)
35
+ }
36
+
37
+ // Node < 19 has no global crypto. Kept as a fallback rather than the default.
38
+ try {
39
+ var nodeCrypto = require('crypto')
40
+ if (nodeCrypto && typeof nodeCrypto.randomBytes === 'function') {
41
+ return nodeCrypto.randomBytes(size)
42
+ }
43
+ } catch (e) { /* no node crypto in this environment */ }
44
+
45
+ throw new Error('bsv: no CSPRNG available in this environment (needs globalThis.crypto.getRandomValues or node crypto)')
9
46
  }
10
47
 
48
+ /**
49
+ * Fill `size` bytes from a WebCrypto instance, respecting the per-call limit.
50
+ * @private
51
+ */
52
+ Random._fromGetRandomValues = function (webcrypto, size) {
53
+ var buf = Buffer.alloc(size)
54
+ for (var offset = 0; offset < size; offset += MAX_GET_RANDOM_VALUES) {
55
+ var chunk = new Uint8Array(Math.min(MAX_GET_RANDOM_VALUES, size - offset))
56
+ webcrypto.getRandomValues(chunk)
57
+ Buffer.from(chunk).copy(buf, offset)
58
+ }
59
+ return buf
60
+ }
61
+
62
+ /**
63
+ * Node-specific CSPRNG. Retained as public API; `getRandomBuffer` no longer routes
64
+ * here by default.
65
+ */
11
66
  Random.getRandomBufferNode = function (size) {
12
67
  var crypto = require('crypto')
13
68
  return crypto.randomBytes(size)
14
69
  }
15
70
 
71
+ /**
72
+ * WebCrypto CSPRNG. Retained as public API.
73
+ *
74
+ * Reads `globalThis` rather than a bare `window`, which does not exist in Web Workers,
75
+ * Node, or React Native.
76
+ */
16
77
  Random.getRandomBufferBrowser = function (size) {
17
- if (!window.crypto && !window.msCrypto) {
18
- throw new Error('window.crypto not available')
78
+ var g = typeof globalThis !== 'undefined' ? globalThis : {}
79
+ var crypto = null
80
+
81
+ if (g.crypto && typeof g.crypto.getRandomValues === 'function') {
82
+ crypto = g.crypto
83
+ } else if (g.msCrypto && typeof g.msCrypto.getRandomValues === 'function') { // internet explorer
84
+ crypto = g.msCrypto
19
85
  }
20
- var crypto
21
86
 
22
- if (window.crypto && window.crypto.getRandomValues) {
23
- crypto = window.crypto
24
- } else if (window.msCrypto && window.msCrypto.getRandomValues) { // internet explorer
25
- crypto = window.msCrypto
26
- } else {
87
+ if (!crypto) {
27
88
  throw new Error('window.crypto.getRandomValues not available')
28
89
  }
29
90
 
30
- var bbuf = new Uint8Array(size)
31
- crypto.getRandomValues(bbuf)
32
- var buf = Buffer.from(bbuf)
33
-
34
- return buf
91
+ return Random._fromGetRandomValues(crypto, size)
35
92
  }
36
93
 
37
94
  module.exports = Random
@@ -58,6 +58,44 @@ async function generateIssuerKeys(opts) {
58
58
  }
59
59
  }
60
60
 
61
+ // The five verification relationships DID Core defines. They exist to be DISTINCT:
62
+ // `authentication` proves who you are right now, `assertionMethod` makes a claim that
63
+ // outlives the session. Keeping them apart is what stops a low-friction login signature
64
+ // from being redeemed as a signed statement.
65
+ //
66
+ // This module used to cross-list every key into both, which erased the distinction and
67
+ // left a caller unable to express "this key may log in but may not make assertions".
68
+ var VERIFICATION_RELATIONSHIPS = [
69
+ 'authentication',
70
+ 'assertionMethod',
71
+ 'keyAgreement',
72
+ 'capabilityInvocation',
73
+ 'capabilityDelegation'
74
+ ]
75
+
76
+ // Preserves the historical output when a key does not say otherwise.
77
+ var DEFAULT_RELATIONSHIPS = ['authentication', 'assertionMethod']
78
+
79
+ /**
80
+ * Resolve the verification relationships for a key descriptor.
81
+ *
82
+ * @param {object} key - `{ kid, jwk, relationships? }`
83
+ * @returns {Array<string>}
84
+ */
85
+ function relationshipsFor (key) {
86
+ var rels = key.relationships || DEFAULT_RELATIONSHIPS
87
+ if (!Array.isArray(rels) || rels.length === 0) {
88
+ throw new Error('relationships must be a non-empty array of DID Core verification relationships')
89
+ }
90
+ rels.forEach(function (rel) {
91
+ if (VERIFICATION_RELATIONSHIPS.indexOf(rel) === -1) {
92
+ throw new Error('unknown verification relationship: ' + rel +
93
+ ' (expected one of ' + VERIFICATION_RELATIONSHIPS.join(', ') + ')')
94
+ }
95
+ })
96
+ return rels
97
+ }
98
+
61
99
  // Build did:web documents (did.json and jwks.json)
62
100
  function buildDidWebDocuments(params) {
63
101
  if (!params.domain) {
@@ -68,6 +106,7 @@ function buildDidWebDocuments(params) {
68
106
  var did = 'did:web:' + domain.replace(/:/g, '%3A')
69
107
 
70
108
  var verificationMethods = []
109
+ var methodRelationships = []
71
110
  var publicKeys = []
72
111
 
73
112
  // Add P-256 key if provided
@@ -79,6 +118,7 @@ function buildDidWebDocuments(params) {
79
118
  publicKeyJwk: params.p256.jwk
80
119
  }
81
120
  verificationMethods.push(p256Method)
121
+ methodRelationships.push(relationshipsFor(params.p256))
82
122
  publicKeys.push(params.p256.jwk)
83
123
  }
84
124
 
@@ -91,6 +131,7 @@ function buildDidWebDocuments(params) {
91
131
  publicKeyJwk: params.k1.jwk
92
132
  }
93
133
  verificationMethods.push(k1Method)
134
+ methodRelationships.push(relationshipsFor(params.k1))
94
135
  publicKeys.push(params.k1.jwk)
95
136
  }
96
137
 
@@ -105,11 +146,19 @@ function buildDidWebDocuments(params) {
105
146
  'https://w3id.org/security/suites/jws-2020/v1'
106
147
  ],
107
148
  id: did,
108
- verificationMethod: verificationMethods,
109
- authentication: verificationMethods.map(function(vm) { return vm.id }),
110
- assertionMethod: verificationMethods.map(function(vm) { return vm.id })
149
+ verificationMethod: verificationMethods
111
150
  }
112
151
 
152
+ // Scope each key to the relationships it was given. Omitting `relationships`
153
+ // reproduces the previous output exactly (every key in both authentication and
154
+ // assertionMethod), so existing callers are unaffected.
155
+ VERIFICATION_RELATIONSHIPS.forEach(function (rel) {
156
+ var ids = verificationMethods
157
+ .filter(function (vm, i) { return methodRelationships[i].indexOf(rel) !== -1 })
158
+ .map(function (vm) { return vm.id })
159
+ if (ids.length) didDocument[rel] = ids
160
+ })
161
+
113
162
  if (params.controllerName) {
114
163
  didDocument.controller = params.controllerName
115
164
  }
@@ -144,6 +193,11 @@ function rotateIssuerKey(params) {
144
193
  publicKeyJwk: params.newKey.jwk
145
194
  }
146
195
 
196
+ // Which relationships this rotation actually replaces. Defaults to both, which is
197
+ // the historical behaviour.
198
+ var rotating = relationshipsFor(params.newKey)
199
+ var current = params.currentDocument || null
200
+
147
201
  // Build updated DID Document with new key as primary
148
202
  var didDocument = {
149
203
  '@context': [
@@ -151,13 +205,38 @@ function rotateIssuerKey(params) {
151
205
  'https://w3id.org/security/suites/jws-2020/v1'
152
206
  ],
153
207
  id: did,
154
- verificationMethod: [newMethod],
155
- authentication: [newMethod.id],
156
- assertionMethod: [newMethod.id],
157
- rotationInfo: {
158
- rotatedAt: new Date().toISOString(),
159
- gracePeriodDays: keepOldForDays
208
+ verificationMethod: [newMethod]
209
+ }
210
+
211
+ // A rotation must not silently reach beyond the relationship being rotated.
212
+ // Replacing a compromised `authentication` key used to rewrite `assertionMethod`
213
+ // too, which invalidates every statement the issuer has ever signed. Relationships
214
+ // outside `rotating` are carried across from `currentDocument` untouched; without a
215
+ // `currentDocument` there is nothing to carry, and the result matches the old output.
216
+ VERIFICATION_RELATIONSHIPS.forEach(function (rel) {
217
+ if (rotating.indexOf(rel) !== -1) {
218
+ didDocument[rel] = [newMethod.id]
219
+ } else if (current && Array.isArray(current[rel]) && current[rel].length) {
220
+ didDocument[rel] = current[rel].slice()
160
221
  }
222
+ })
223
+
224
+ // Keep the verification methods those carried-over relationships still point at,
225
+ // otherwise the document references key ids it does not define. The rotated-out key
226
+ // drops out here automatically: nothing references it any more.
227
+ if (current && Array.isArray(current.verificationMethod)) {
228
+ var referenced = {}
229
+ VERIFICATION_RELATIONSHIPS.forEach(function (rel) {
230
+ (didDocument[rel] || []).forEach(function (id) { referenced[id] = true })
231
+ })
232
+ current.verificationMethod.forEach(function (vm) {
233
+ if (referenced[vm.id] && vm.id !== newMethod.id) didDocument.verificationMethod.push(vm)
234
+ })
235
+ }
236
+
237
+ didDocument.rotationInfo = {
238
+ rotatedAt: new Date().toISOString(),
239
+ gracePeriodDays: keepOldForDays
161
240
  }
162
241
 
163
242
  var jwks = {
@@ -1,7 +1,6 @@
1
1
  'use strict'
2
2
 
3
3
  var _ = require('../util/_')
4
- var bs58 = require('bs58')
5
4
  var buffer = require('buffer')
6
5
 
7
6
  /**
@@ -11,6 +10,71 @@ var buffer = require('buffer')
11
10
  */
12
11
  var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split('')
13
12
 
13
+ // Reverse lookup for decoding. Built from ALPHABET so the two cannot disagree.
14
+ var ALPHABET_MAP = {}
15
+ for (var _i = 0; _i < ALPHABET.length; _i++) ALPHABET_MAP[ALPHABET[_i]] = _i
16
+
17
+ /**
18
+ * Base58 encode/decode, replacing the `bs58` dependency (which also pulled `base-x`).
19
+ *
20
+ * This is the standard big-number-in-base-58 conversion: repeatedly multiply the
21
+ * accumulator by 256 (encode) or 58 (decode) and carry. Two details are where
22
+ * implementations usually go wrong, and both are exercised by the differential test in
23
+ * test/encoding/base58.js:
24
+ *
25
+ * - Leading zero bytes are NOT part of the number — they are significant and each one
26
+ * maps to a literal '1'. Dropping them silently truncates an address.
27
+ * - The carry loops must run to completion before the next digit, or long inputs lose
28
+ * the high-order bytes.
29
+ *
30
+ * These functions encode and decode addresses and WIF private keys, so they were
31
+ * verified by differential test against bs58 across 20,000 random inputs — including
32
+ * every leading-zero-count from 0 to 8 — before the dependency was removed.
33
+ */
34
+ function base58encode (buf) {
35
+ if (buf.length === 0) return ''
36
+ var digits = [0]
37
+ var i, j, carry
38
+ for (i = 0; i < buf.length; i++) {
39
+ for (j = 0, carry = buf[i]; j < digits.length; j++) {
40
+ carry += digits[j] << 8
41
+ digits[j] = carry % 58
42
+ carry = (carry / 58) | 0
43
+ }
44
+ while (carry > 0) {
45
+ digits.push(carry % 58)
46
+ carry = (carry / 58) | 0
47
+ }
48
+ }
49
+ var out = ''
50
+ // Each leading zero byte is a significant '1', not part of the number.
51
+ for (i = 0; buf[i] === 0 && i < buf.length - 1; i++) out += ALPHABET[0]
52
+ for (i = digits.length - 1; i >= 0; i--) out += ALPHABET[digits[i]]
53
+ return out
54
+ }
55
+
56
+ function base58decode (str) {
57
+ if (str.length === 0) return Buffer.alloc(0)
58
+ var bytes = [0]
59
+ var i, j, carry
60
+ for (i = 0; i < str.length; i++) {
61
+ var value = ALPHABET_MAP[str[i]]
62
+ if (value === undefined) throw new Error('Non-base58 character')
63
+ for (j = 0, carry = value; j < bytes.length; j++) {
64
+ carry += bytes[j] * 58
65
+ bytes[j] = carry & 0xff
66
+ carry >>= 8
67
+ }
68
+ while (carry > 0) {
69
+ bytes.push(carry & 0xff)
70
+ carry >>= 8
71
+ }
72
+ }
73
+ // Mirror of the encode side: each leading '1' is a zero byte.
74
+ for (i = 0; str[i] === ALPHABET[0] && i < str.length - 1; i++) bytes.push(0)
75
+ return Buffer.from(bytes.reverse())
76
+ }
77
+
14
78
  /**
15
79
  * A Base58 object can encode/decoded Base 58, which is used primarily for
16
80
  * string-formatted Bitcoin addresses and private keys. Addresses and private
@@ -54,7 +118,7 @@ Base58.encode = function (buf) {
54
118
  if (!buffer.Buffer.isBuffer(buf)) {
55
119
  throw new Error('Input should be a buffer')
56
120
  }
57
- return bs58.encode(buf)
121
+ return base58encode(buf)
58
122
  }
59
123
 
60
124
  /**
@@ -67,7 +131,7 @@ Base58.decode = function (str) {
67
131
  if (typeof str !== 'string') {
68
132
  throw new Error('Input should be a string')
69
133
  }
70
- return Buffer.from(bs58.decode(str))
134
+ return base58decode(str)
71
135
  }
72
136
 
73
137
  Base58.prototype.fromBuffer = function (buf) {
@@ -2,7 +2,6 @@
2
2
 
3
3
  var HDPrivateKey = require('../hdprivatekey')
4
4
  var BN = require('../crypto/bn')
5
- var unorm = require('unorm')
6
5
  var _ = require('../util/_')
7
6
 
8
7
  var pbkdf2 = require('./pbkdf2')
@@ -16,6 +15,21 @@ var Random = require('../crypto/random')
16
15
 
17
16
  var $ = require('../util/preconditions')
18
17
 
18
+ /**
19
+ * NFKD-normalise a mnemonic or passphrase, as BIP-39 requires before PBKDF2.
20
+ *
21
+ * Replaces the `unorm` dependency: `String.prototype.normalize` has been in the language
22
+ * since ES6 and this package requires Node >= 20.19, so the shim was redundant.
23
+ *
24
+ * Non-strings return '' so that `Mnemonic.isValid(garbage)` answers false instead of
25
+ * throwing. unorm was inconsistent about this — `[]` and `{}` returned '' while `['a']`
26
+ * and a Buffer threw — and a validity predicate that fails closed for every non-string
27
+ * is both the safer answer and the coherent one.
28
+ */
29
+ function nfkd (str) {
30
+ return typeof str === 'string' ? str.normalize('NFKD') : ''
31
+ }
32
+
19
33
  /**
20
34
  * This is an immutable class that represents a BIP39 Mnemonic code.
21
35
  * See BIP39 specification for more info: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
@@ -52,7 +66,7 @@ var Mnemonic = function (data, wordlist) {
52
66
  if (Buffer.isBuffer(data)) {
53
67
  seed = data
54
68
  } else if (_.isString(data)) {
55
- phrase = unorm.nfkd(data)
69
+ phrase = nfkd(data)
56
70
  } else if (_.isNumber(data)) {
57
71
  ent = data
58
72
  } else if (data) {
@@ -145,7 +159,7 @@ Mnemonic.Words = require('./words')
145
159
  * @returns {boolean}
146
160
  */
147
161
  Mnemonic.isValid = function (mnemonic, wordlist) {
148
- mnemonic = unorm.nfkd(mnemonic)
162
+ mnemonic = nfkd(mnemonic)
149
163
  wordlist = wordlist || Mnemonic._getDictionary(mnemonic)
150
164
 
151
165
  if (!wordlist) {
@@ -179,7 +193,7 @@ Mnemonic.isValid = function (mnemonic, wordlist) {
179
193
  * @returns {boolean}
180
194
  */
181
195
  Mnemonic._belongsToWordlist = function (mnemonic, wordlist) {
182
- var words = unorm.nfkd(mnemonic).split(' ')
196
+ var words = nfkd(mnemonic).split(' ')
183
197
  for (var i = 0; i < words.length; i++) {
184
198
  var ind = wordlist.indexOf(words[i])
185
199
  if (ind < 0) return false
@@ -217,7 +231,7 @@ Mnemonic._getDictionary = function (mnemonic) {
217
231
  */
218
232
  Mnemonic.prototype.toSeed = function (passphrase) {
219
233
  passphrase = passphrase || ''
220
- return pbkdf2(unorm.nfkd(this.phrase), unorm.nfkd('mnemonic' + passphrase), 2048, 64)
234
+ return pbkdf2(nfkd(this.phrase), nfkd('mnemonic' + passphrase), 2048, 64)
221
235
  }
222
236
 
223
237
  /**
@@ -1,2 +1,35 @@
1
- if (process.browser) module.exports = require('./pbkdf2.browser')
2
- else module.exports = require('./pbkdf2.node')
1
+ 'use strict'
2
+
3
+ // Pick the PBKDF2 backend by CAPABILITY, not by `process.browser`. Same reasoning as
4
+ // lib/crypto/hash.js: that flag is undefined in React Native, Deno, Workers and Bun, so
5
+ // all of them took the node branch and required('crypto') — failing outright, or
6
+ // resolving to a partial shim.
7
+ //
8
+ // The node variant needs `createHmac('sha512')`, so that is what is probed, and the
9
+ // result is checked against RFC 4231 test case 1 rather than merely existing. A shim
10
+ // that returns a wrong or stubbed HMAC would otherwise silently corrupt every seed
11
+ // derived from a mnemonic — and unlike a crash, that failure is invisible until funds
12
+ // are missing. The pure-JS fallback is audited and always safe.
13
+
14
+ var RFC4231_CASE1 = '87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854'
15
+
16
+ function nodeHmacIsUsable () {
17
+ var crypto
18
+ try {
19
+ crypto = require('crypto')
20
+ } catch (e) {
21
+ return false
22
+ }
23
+ if (!crypto || typeof crypto.createHmac !== 'function') return false
24
+
25
+ try {
26
+ var mac = crypto.createHmac('sha512', Buffer.alloc(20, 0x0b))
27
+ .update('Hi There')
28
+ .digest('hex')
29
+ return mac === RFC4231_CASE1
30
+ } catch (e) {
31
+ return false
32
+ }
33
+ }
34
+
35
+ module.exports = nodeHmacIsUsable() ? require('./pbkdf2.node') : require('./pbkdf2.browser')