smartledger-bsv 3.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 (76) hide show
  1. package/LICENSE +36 -0
  2. package/README.md +305 -0
  3. package/SECURITY.md +75 -0
  4. package/bsv-ecies.min.js +12 -0
  5. package/bsv-message.min.js +10 -0
  6. package/bsv-mnemonic.min.js +12 -0
  7. package/bsv.d.ts +440 -0
  8. package/bsv.min.js +37 -0
  9. package/ecies/index.js +1 -0
  10. package/index.js +101 -0
  11. package/lib/address.js +526 -0
  12. package/lib/block/block.js +277 -0
  13. package/lib/block/blockheader.js +294 -0
  14. package/lib/block/index.js +4 -0
  15. package/lib/block/merkleblock.js +316 -0
  16. package/lib/crypto/bn.js +278 -0
  17. package/lib/crypto/ecdsa.js +330 -0
  18. package/lib/crypto/elliptic-fixed.js +74 -0
  19. package/lib/crypto/hash.browser.js +171 -0
  20. package/lib/crypto/hash.js +2 -0
  21. package/lib/crypto/hash.node.js +171 -0
  22. package/lib/crypto/point.js +217 -0
  23. package/lib/crypto/random.js +37 -0
  24. package/lib/crypto/signature.js +410 -0
  25. package/lib/crypto/smartledger_verify.js +109 -0
  26. package/lib/ecies/bitcore-ecies.js +163 -0
  27. package/lib/ecies/electrum-ecies.js +175 -0
  28. package/lib/ecies/errors.js +16 -0
  29. package/lib/ecies/index.js +1 -0
  30. package/lib/encoding/base58.js +108 -0
  31. package/lib/encoding/base58check.js +112 -0
  32. package/lib/encoding/bufferreader.js +200 -0
  33. package/lib/encoding/bufferwriter.js +150 -0
  34. package/lib/encoding/varint.js +71 -0
  35. package/lib/errors/index.js +57 -0
  36. package/lib/errors/spec.js +184 -0
  37. package/lib/hdprivatekey.js +655 -0
  38. package/lib/hdpublickey.js +509 -0
  39. package/lib/message/index.js +4 -0
  40. package/lib/message/message.js +181 -0
  41. package/lib/mnemonic/errors.js +18 -0
  42. package/lib/mnemonic/index.js +4 -0
  43. package/lib/mnemonic/mnemonic.js +304 -0
  44. package/lib/mnemonic/pbkdf2.js +68 -0
  45. package/lib/mnemonic/words/chinese.js +5 -0
  46. package/lib/mnemonic/words/english.js +5 -0
  47. package/lib/mnemonic/words/french.js +5 -0
  48. package/lib/mnemonic/words/index.js +8 -0
  49. package/lib/mnemonic/words/italian.js +5 -0
  50. package/lib/mnemonic/words/japanese.js +5 -0
  51. package/lib/mnemonic/words/spanish.js +5 -0
  52. package/lib/networks.js +392 -0
  53. package/lib/opcode.js +248 -0
  54. package/lib/privatekey.js +373 -0
  55. package/lib/publickey.js +387 -0
  56. package/lib/script/index.js +3 -0
  57. package/lib/script/interpreter.js +1807 -0
  58. package/lib/script/script.js +1153 -0
  59. package/lib/transaction/index.js +7 -0
  60. package/lib/transaction/input/index.js +6 -0
  61. package/lib/transaction/input/input.js +202 -0
  62. package/lib/transaction/input/multisig.js +220 -0
  63. package/lib/transaction/input/multisigscripthash.js +189 -0
  64. package/lib/transaction/input/publickey.js +96 -0
  65. package/lib/transaction/input/publickeyhash.js +103 -0
  66. package/lib/transaction/output.js +192 -0
  67. package/lib/transaction/sighash.js +288 -0
  68. package/lib/transaction/signature.js +88 -0
  69. package/lib/transaction/transaction.js +1208 -0
  70. package/lib/transaction/unspentoutput.js +97 -0
  71. package/lib/util/_.js +44 -0
  72. package/lib/util/js.js +91 -0
  73. package/lib/util/preconditions.js +34 -0
  74. package/message/index.js +1 -0
  75. package/mnemonic/index.js +1 -0
  76. package/package.json +86 -0
@@ -0,0 +1,410 @@
1
+ 'use strict'
2
+
3
+ var BN = require('./bn')
4
+ var _ = require('../util/_')
5
+ var $ = require('../util/preconditions')
6
+ var JSUtil = require('../util/js')
7
+
8
+ var Signature = function Signature (r, s) {
9
+ if (!(this instanceof Signature)) {
10
+ return new Signature(r, s)
11
+ }
12
+ if (r instanceof BN) {
13
+ this.set({
14
+ r: r,
15
+ s: s
16
+ })
17
+ } else if (r) {
18
+ var obj = r
19
+ this.set(obj)
20
+ }
21
+ }
22
+
23
+ Signature.prototype.set = function (obj) {
24
+ this.r = obj.r || this.r || undefined
25
+ this.s = obj.s || this.s || undefined
26
+
27
+ this.i = typeof obj.i !== 'undefined' ? obj.i : this.i // public key recovery parameter in range [0, 3]
28
+ this.compressed = typeof obj.compressed !== 'undefined'
29
+ ? obj.compressed : this.compressed // whether the recovered pubkey is compressed
30
+ this.nhashtype = obj.nhashtype || this.nhashtype || undefined
31
+ return this
32
+ }
33
+
34
+ Signature.fromCompact = function (buf) {
35
+ $.checkArgument(Buffer.isBuffer(buf), 'Argument is expected to be a Buffer')
36
+
37
+ var sig = new Signature()
38
+
39
+ var compressed = true
40
+ var i = buf.slice(0, 1)[0] - 27 - 4
41
+ if (i < 0) {
42
+ compressed = false
43
+ i = i + 4
44
+ }
45
+
46
+ var b2 = buf.slice(1, 33)
47
+ var b3 = buf.slice(33, 65)
48
+
49
+ $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be 0, 1, 2, or 3'))
50
+ $.checkArgument(b2.length === 32, new Error('r must be 32 bytes'))
51
+ $.checkArgument(b3.length === 32, new Error('s must be 32 bytes'))
52
+
53
+ sig.compressed = compressed
54
+ sig.i = i
55
+ sig.r = BN.fromBuffer(b2)
56
+ sig.s = BN.fromBuffer(b3)
57
+
58
+ return sig
59
+ }
60
+
61
+ Signature.fromDER = Signature.fromBuffer = function (buf, strict) {
62
+ var obj = Signature.parseDER(buf, strict)
63
+ var sig = new Signature()
64
+
65
+ sig.r = obj.r
66
+ sig.s = obj.s
67
+
68
+ return sig
69
+ }
70
+
71
+ // The format used in a tx
72
+ Signature.fromTxFormat = function (buf) {
73
+ var nhashtype = buf.readUInt8(buf.length - 1)
74
+ var derbuf = buf.slice(0, buf.length - 1)
75
+ var sig = Signature.fromDER(derbuf, false)
76
+ sig.nhashtype = nhashtype
77
+ return sig
78
+ }
79
+
80
+ Signature.fromString = function (str) {
81
+ var buf = Buffer.from(str, 'hex')
82
+ return Signature.fromDER(buf)
83
+ }
84
+
85
+ /**
86
+ * In order to mimic the non-strict DER encoding of OpenSSL, set strict = false.
87
+ */
88
+ Signature.parseDER = function (buf, strict) {
89
+ $.checkArgument(Buffer.isBuffer(buf), new Error('DER formatted signature should be a buffer'))
90
+ if (_.isUndefined(strict)) {
91
+ strict = true
92
+ }
93
+
94
+ var header = buf[0]
95
+ $.checkArgument(header === 0x30, new Error('Header byte should be 0x30'))
96
+
97
+ var length = buf[1]
98
+ var buflength = buf.slice(2).length
99
+ $.checkArgument(!strict || length === buflength, new Error('Length byte should length of what follows'))
100
+
101
+ length = length < buflength ? length : buflength
102
+
103
+ var rheader = buf[2 + 0]
104
+ $.checkArgument(rheader === 0x02, new Error('Integer byte for r should be 0x02'))
105
+
106
+ var rlength = buf[2 + 1]
107
+ var rbuf = buf.slice(2 + 2, 2 + 2 + rlength)
108
+ var r = BN.fromBuffer(rbuf)
109
+ var rneg = buf[2 + 1 + 1] === 0x00
110
+ $.checkArgument(rlength === rbuf.length, new Error('Length of r incorrect'))
111
+
112
+ var sheader = buf[2 + 2 + rlength + 0]
113
+ $.checkArgument(sheader === 0x02, new Error('Integer byte for s should be 0x02'))
114
+
115
+ var slength = buf[2 + 2 + rlength + 1]
116
+ var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength)
117
+ var s = BN.fromBuffer(sbuf)
118
+ var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00
119
+ $.checkArgument(slength === sbuf.length, new Error('Length of s incorrect'))
120
+
121
+ var sumlength = 2 + 2 + rlength + 2 + slength
122
+ $.checkArgument(length === sumlength - 2, new Error('Length of signature incorrect'))
123
+
124
+ var obj = {
125
+ header: header,
126
+ length: length,
127
+ rheader: rheader,
128
+ rlength: rlength,
129
+ rneg: rneg,
130
+ rbuf: rbuf,
131
+ r: r,
132
+ sheader: sheader,
133
+ slength: slength,
134
+ sneg: sneg,
135
+ sbuf: sbuf,
136
+ s: s
137
+ }
138
+
139
+ return obj
140
+ }
141
+
142
+ Signature.prototype.toCompact = function (i, compressed) {
143
+ i = typeof i === 'number' ? i : this.i
144
+ compressed = typeof compressed === 'boolean' ? compressed : this.compressed
145
+
146
+ if (!(i === 0 || i === 1 || i === 2 || i === 3)) {
147
+ throw new Error('i must be equal to 0, 1, 2, or 3')
148
+ }
149
+
150
+ var val = i + 27 + 4
151
+ if (compressed === false) {
152
+ val = val - 4
153
+ }
154
+ var b1 = Buffer.from([val])
155
+ var b2 = this.r.toBuffer({
156
+ size: 32
157
+ })
158
+ var b3 = this.s.toBuffer({
159
+ size: 32
160
+ })
161
+ return Buffer.concat([b1, b2, b3])
162
+ }
163
+
164
+ Signature.prototype.toBuffer = Signature.prototype.toDER = function () {
165
+ var rnbuf = this.r.toBuffer()
166
+ var snbuf = this.s.toBuffer()
167
+
168
+ var rneg = !!(rnbuf[0] & 0x80)
169
+ var sneg = !!(snbuf[0] & 0x80)
170
+
171
+ var rbuf = rneg ? Buffer.concat([Buffer.from([0x00]), rnbuf]) : rnbuf
172
+ var sbuf = sneg ? Buffer.concat([Buffer.from([0x00]), snbuf]) : snbuf
173
+
174
+ var rlength = rbuf.length
175
+ var slength = sbuf.length
176
+ var length = 2 + rlength + 2 + slength
177
+ var rheader = 0x02
178
+ var sheader = 0x02
179
+ var header = 0x30
180
+
181
+ var der = Buffer.concat([Buffer.from([header, length, rheader, rlength]), rbuf, Buffer.from([sheader, slength]), sbuf])
182
+ return der
183
+ }
184
+
185
+ Signature.prototype.toString = function () {
186
+ var buf = this.toDER()
187
+ return buf.toString('hex')
188
+ }
189
+
190
+ /**
191
+ * This function is translated from bitcoind's IsDERSignature and is used in
192
+ * the script interpreter. This "DER" format actually includes an extra byte,
193
+ * the nhashtype, at the end. It is really the tx format, not DER format.
194
+ *
195
+ * A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S] [hashtype]
196
+ * Where R and S are not negative (their first byte has its highest bit not set), and not
197
+ * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
198
+ * in which case a single 0 byte is necessary and even required).
199
+ *
200
+ * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
201
+ */
202
+ Signature.isTxDER = function (buf) {
203
+ if (buf.length < 9) {
204
+ // Non-canonical signature: too short
205
+ return false
206
+ }
207
+ if (buf.length > 73) {
208
+ // Non-canonical signature: too long
209
+ return false
210
+ }
211
+ if (buf[0] !== 0x30) {
212
+ // Non-canonical signature: wrong type
213
+ return false
214
+ }
215
+ if (buf[1] !== buf.length - 3) {
216
+ // Non-canonical signature: wrong length marker
217
+ return false
218
+ }
219
+ var nLenR = buf[3]
220
+ if (5 + nLenR >= buf.length) {
221
+ // Non-canonical signature: S length misplaced
222
+ return false
223
+ }
224
+ var nLenS = buf[5 + nLenR]
225
+ if ((nLenR + nLenS + 7) !== buf.length) {
226
+ // Non-canonical signature: R+S length mismatch
227
+ return false
228
+ }
229
+
230
+ var R = buf.slice(4)
231
+ if (buf[4 - 2] !== 0x02) {
232
+ // Non-canonical signature: R value type mismatch
233
+ return false
234
+ }
235
+ if (nLenR === 0) {
236
+ // Non-canonical signature: R length is zero
237
+ return false
238
+ }
239
+ if (R[0] & 0x80) {
240
+ // Non-canonical signature: R value negative
241
+ return false
242
+ }
243
+ if (nLenR > 1 && (R[0] === 0x00) && !(R[1] & 0x80)) {
244
+ // Non-canonical signature: R value excessively padded
245
+ return false
246
+ }
247
+
248
+ var S = buf.slice(6 + nLenR)
249
+ if (buf[6 + nLenR - 2] !== 0x02) {
250
+ // Non-canonical signature: S value type mismatch
251
+ return false
252
+ }
253
+ if (nLenS === 0) {
254
+ // Non-canonical signature: S length is zero
255
+ return false
256
+ }
257
+ if (S[0] & 0x80) {
258
+ // Non-canonical signature: S value negative
259
+ return false
260
+ }
261
+ if (nLenS > 1 && (S[0] === 0x00) && !(S[1] & 0x80)) {
262
+ // Non-canonical signature: S value excessively padded
263
+ return false
264
+ }
265
+ return true
266
+ }
267
+
268
+ /**
269
+ * Compares to bitcoind's IsLowDERSignature
270
+ * See also ECDSA signature algorithm which enforces this.
271
+ * See also BIP 62, "low S values in signatures"
272
+ */
273
+ Signature.prototype.hasLowS = function () {
274
+ if (this.s.lt(new BN(1)) ||
275
+ this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex'))) {
276
+ return false
277
+ }
278
+ return true
279
+ }
280
+
281
+ /**
282
+ * @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof.
283
+ * Translated from bitcoind's IsDefinedHashtypeSignature
284
+ */
285
+ Signature.prototype.hasDefinedHashtype = function () {
286
+ if (!JSUtil.isNaturalNumber(this.nhashtype)) {
287
+ return false
288
+ }
289
+ // accept with or without Signature.SIGHASH_ANYONECANPAY by ignoring the bit
290
+ var temp = this.nhashtype & 0x1F
291
+ if (temp < Signature.SIGHASH_ALL || temp > Signature.SIGHASH_SINGLE) {
292
+ return false
293
+ }
294
+ return true
295
+ }
296
+
297
+ Signature.prototype.toTxFormat = function () {
298
+ var derbuf = this.toDER()
299
+ var buf = Buffer.alloc(1)
300
+ buf.writeUInt8(this.nhashtype, 0)
301
+ return Buffer.concat([derbuf, buf])
302
+ }
303
+
304
+ Signature.SIGHASH_ALL = 0x01
305
+ Signature.SIGHASH_NONE = 0x02
306
+ Signature.SIGHASH_SINGLE = 0x03
307
+ Signature.SIGHASH_FORKID = 0x40
308
+ Signature.SIGHASH_ANYONECANPAY = 0x80
309
+
310
+ // === SmartLedger Security Enhancement Methods ===
311
+
312
+ /**
313
+ * Check if signature is canonical (s <= n/2) - SmartLedger security feature
314
+ */
315
+ Signature.prototype.isCanonical = function () {
316
+ var Point = require('./point')
317
+ var nh = Point.getN().shrn(1) // n/2
318
+ return this.s.lte(nh)
319
+ }
320
+
321
+ /**
322
+ * Return canonicalized version of signature - SmartLedger security feature
323
+ */
324
+ Signature.prototype.toCanonical = function () {
325
+ if (this.isCanonical()) {
326
+ return new Signature({ r: this.r, s: this.s, i: this.i, compressed: this.compressed, nhashtype: this.nhashtype })
327
+ }
328
+
329
+ var Point = require('./point')
330
+ var n = Point.getN()
331
+ var canonicalS = n.sub(this.s)
332
+
333
+ return new Signature({ r: this.r, s: canonicalS, i: this.i, compressed: this.compressed, nhashtype: this.nhashtype })
334
+ }
335
+
336
+ /**
337
+ * Validate signature parameters - SmartLedger security feature
338
+ */
339
+ Signature.prototype.validate = function () {
340
+ if (!this.r || !this.s) {
341
+ throw new Error('Signature missing r or s component')
342
+ }
343
+
344
+ if (this.r.isZero()) {
345
+ throw new Error('Signature r component is zero')
346
+ }
347
+
348
+ if (this.s.isZero()) {
349
+ throw new Error('Signature s component is zero')
350
+ }
351
+
352
+ var Point = require('./point')
353
+ var n = Point.getN()
354
+
355
+ if (this.r.gte(n)) {
356
+ throw new Error('Signature r component >= curve order')
357
+ }
358
+
359
+ if (this.s.gte(n)) {
360
+ throw new Error('Signature s component >= curve order')
361
+ }
362
+
363
+ if (this.r.isNeg()) {
364
+ throw new Error('Signature r component is negative')
365
+ }
366
+
367
+ if (this.s.isNeg()) {
368
+ throw new Error('Signature s component is negative')
369
+ }
370
+
371
+ return true
372
+ }
373
+
374
+ /**
375
+ * Boolean signature validation - SmartLedger security feature
376
+ */
377
+ Signature.prototype.isValid = function () {
378
+ try {
379
+ this.validate()
380
+ return true
381
+ } catch (e) {
382
+ return false
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Apply SmartLedger security canonicalization - called during crypto operations
388
+ */
389
+ Signature.prototype.applySecurityPatches = function () {
390
+ var Point = require('./point')
391
+ var n = Point.getN()
392
+ var nh = n.shrn(1) // n/2
393
+
394
+ // Security validation
395
+ if (this.r.isZero() || this.s.isZero()) {
396
+ throw new Error('Invalid signature: zero r or s')
397
+ }
398
+ if (this.r.gte(n) || this.s.gte(n)) {
399
+ throw new Error('Invalid signature: out of range')
400
+ }
401
+
402
+ // Canonicalize s value (anti-malleability)
403
+ if (this.s.gt(nh)) {
404
+ this.s = n.sub(this.s)
405
+ }
406
+
407
+ return this
408
+ }
409
+
410
+ module.exports = Signature
@@ -0,0 +1,109 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * SmartLedger Hardened Verification Module
5
+ * Provides secure ECDSA signature verification with malleability protection
6
+ */
7
+
8
+ const BN = require('./bn')
9
+ const Point = require('./point')
10
+ const ECDSA = require('./ecdsa')
11
+
12
+ // Cache curve constants for performance
13
+ const n = Point.getN()
14
+ const nh = n.shrn(1) // n / 2
15
+
16
+ /**
17
+ * Hardened signature verification with canonicalization
18
+ * @param {Buffer} msgHash - 32-byte message hash
19
+ * @param {Signature} sig - Signature object with r,s components
20
+ * @param {PublicKey} pubkey - Public key for verification
21
+ * @returns {boolean} - true if signature is valid and canonical
22
+ */
23
+ function smartVerify (msgHash, sig, pubkey) {
24
+ // Strict input validation
25
+ if (!Buffer.isBuffer(msgHash) || msgHash.length !== 32) {
26
+ throw new Error('Invalid message hash: must be 32-byte buffer')
27
+ }
28
+
29
+ if (!sig || !sig.r || !sig.s) {
30
+ return false
31
+ }
32
+
33
+ // Ensure r and s are BN instances
34
+ const r = BN.isBN(sig.r) ? sig.r : new BN(sig.r)
35
+ const s = BN.isBN(sig.s) ? sig.s : new BN(sig.s)
36
+
37
+ // Reject zero values
38
+ if (r.isZero() || s.isZero()) {
39
+ return false
40
+ }
41
+
42
+ // Reject values >= n (curve order)
43
+ if (r.gte(n) || s.gte(n)) {
44
+ return false
45
+ }
46
+
47
+ // Canonicalize s to lower half (anti-malleability)
48
+ let canonicalS = s
49
+ if (s.gt(nh)) {
50
+ canonicalS = n.sub(s)
51
+ }
52
+
53
+ // Create canonicalized signature object
54
+ const canonicalSig = {
55
+ r: r,
56
+ s: canonicalS
57
+ }
58
+
59
+ // Use BSV's original ECDSA verify with canonical signature
60
+ return ECDSA.verify(msgHash, canonicalSig, pubkey)
61
+ }
62
+
63
+ /**
64
+ * Check if signature is in canonical form (s <= n/2)
65
+ * @param {Object} sig - Signature with r,s components
66
+ * @returns {boolean} - true if signature is canonical
67
+ */
68
+ function isCanonical (sig) {
69
+ if (!sig || !sig.s) {
70
+ return false
71
+ }
72
+
73
+ const s = BN.isBN(sig.s) ? sig.s : new BN(sig.s)
74
+ return s.lte(nh)
75
+ }
76
+
77
+ /**
78
+ * Canonicalize signature to ensure s <= n/2
79
+ * @param {Object} sig - Signature object to canonicalize
80
+ * @returns {Object} - New signature object with canonical s
81
+ */
82
+ function canonicalize (sig) {
83
+ if (!sig || !sig.r || !sig.s) {
84
+ throw new Error('Invalid signature object')
85
+ }
86
+
87
+ const r = BN.isBN(sig.r) ? sig.r : new BN(sig.r)
88
+ const s = BN.isBN(sig.s) ? sig.s : new BN(sig.s)
89
+
90
+ let canonicalS = s
91
+ if (s.gt(nh)) {
92
+ canonicalS = n.sub(s)
93
+ }
94
+
95
+ return {
96
+ r: r,
97
+ s: canonicalS
98
+ }
99
+ }
100
+
101
+ module.exports = {
102
+ smartVerify,
103
+ isCanonical,
104
+ canonicalize,
105
+ constants: {
106
+ n: n,
107
+ nh: nh
108
+ }
109
+ }
@@ -0,0 +1,163 @@
1
+ 'use strict'
2
+
3
+ var bsv = require('../../')
4
+
5
+ var PublicKey = bsv.PublicKey
6
+ var Hash = bsv.crypto.Hash
7
+ var $ = bsv.util.preconditions
8
+ var aesjs = require('aes-js')
9
+ var CBC = aesjs.ModeOfOperation.cbc
10
+ var Random = bsv.crypto.Random
11
+
12
+ var AESCBC = function AESCBC () {}
13
+
14
+ AESCBC.encrypt = function (messagebuf, cipherkeybuf, ivbuf) {
15
+ $.checkArgument(messagebuf)
16
+ $.checkArgument(cipherkeybuf)
17
+ $.checkArgument(ivbuf)
18
+ ivbuf = ivbuf || Random.getRandomBuffer(128 / 8)
19
+ messagebuf = aesjs.padding.pkcs7.pad(messagebuf)
20
+ var aesCbc = new CBC(cipherkeybuf, ivbuf)
21
+ var ctbuf = aesCbc.encrypt(messagebuf)
22
+ var encbuf = Buffer.concat([ivbuf, ctbuf])
23
+ return encbuf
24
+ }
25
+
26
+ AESCBC.decrypt = function (encbuf, cipherkeybuf) {
27
+ $.checkArgument(encbuf)
28
+ $.checkArgument(cipherkeybuf)
29
+ var ivbuf = encbuf.slice(0, 128 / 8)
30
+ var ctbuf = encbuf.slice(128 / 8)
31
+ var aesCbc = new CBC(cipherkeybuf, ivbuf)
32
+ var messagebuf = aesCbc.decrypt(ctbuf)
33
+ messagebuf = aesjs.padding.pkcs7.strip(messagebuf)
34
+ return Buffer.from(messagebuf)
35
+ }
36
+
37
+ // http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme
38
+ var ECIES = function ECIES (opts) {
39
+ if (!(this instanceof ECIES)) {
40
+ return new ECIES()
41
+ }
42
+ this.opts = opts || {}
43
+ }
44
+
45
+ ECIES.prototype.privateKey = function (privateKey) {
46
+ $.checkArgument(privateKey, 'no private key provided')
47
+
48
+ this._privateKey = privateKey || null
49
+
50
+ return this
51
+ }
52
+
53
+ ECIES.prototype.publicKey = function (publicKey) {
54
+ $.checkArgument(publicKey, 'no public key provided')
55
+
56
+ this._publicKey = publicKey || null
57
+
58
+ return this
59
+ }
60
+
61
+ var cachedProperty = function (name, getter) {
62
+ var cachedName = '_' + name
63
+ Object.defineProperty(ECIES.prototype, name, {
64
+ configurable: false,
65
+ enumerable: true,
66
+ get: function () {
67
+ var value = this[cachedName]
68
+ if (!value) {
69
+ value = this[cachedName] = getter.apply(this)
70
+ }
71
+ return value
72
+ }
73
+ })
74
+ }
75
+
76
+ cachedProperty('Rbuf', function () {
77
+ return this._privateKey.publicKey.toDER(true)
78
+ })
79
+
80
+ cachedProperty('kEkM', function () {
81
+ var r = this._privateKey.bn
82
+ var KB = this._publicKey.point
83
+ var P = KB.mul(r)
84
+ var S = P.getX()
85
+ var Sbuf = S.toBuffer({ size: 32 })
86
+ return Hash.sha512(Sbuf)
87
+ })
88
+
89
+ cachedProperty('kE', function () {
90
+ return this.kEkM.slice(0, 32)
91
+ })
92
+
93
+ cachedProperty('kM', function () {
94
+ return this.kEkM.slice(32, 64)
95
+ })
96
+
97
+ // Encrypts the message (String or Buffer).
98
+ // Optional `ivbuf` contains 16-byte Buffer to be used in AES-CBC.
99
+ // By default, `ivbuf` is computed deterministically from message and private key using HMAC-SHA256.
100
+ // Deterministic IV enables end-to-end test vectors for alternative implementations.
101
+ // Note that identical messages have identical ciphertexts. If your protocol does not include some
102
+ // kind of a sequence identifier inside the message *and* it is important to not allow attacker to learn
103
+ // that message is repeated, then you should use custom IV.
104
+ // For random IV, pass `Random.getRandomBuffer(16)` for the second argument.
105
+ ECIES.prototype.encrypt = function (message, ivbuf) {
106
+ if (!Buffer.isBuffer(message)) message = Buffer.from(message)
107
+ if (ivbuf === undefined) {
108
+ ivbuf = Hash.sha256hmac(message, this._privateKey.toBuffer()).slice(0, 16)
109
+ }
110
+ var c = AESCBC.encrypt(message, this.kE, ivbuf)
111
+ var d = Hash.sha256hmac(c, this.kM)
112
+ if (this.opts.shortTag) d = d.slice(0, 4)
113
+ var encbuf
114
+ if (this.opts.noKey) {
115
+ encbuf = Buffer.concat([c, d])
116
+ } else {
117
+ encbuf = Buffer.concat([this.Rbuf, c, d])
118
+ }
119
+ return encbuf
120
+ }
121
+
122
+ ECIES.prototype.decrypt = function (encbuf) {
123
+ $.checkArgument(encbuf)
124
+ var offset = 0
125
+ var tagLength = 32
126
+ if (this.opts.shortTag) {
127
+ tagLength = 4
128
+ }
129
+ if (!this.opts.noKey) {
130
+ var pub
131
+ switch (encbuf[0]) {
132
+ case 4:
133
+ pub = encbuf.slice(0, 65)
134
+ break
135
+ case 3:
136
+ case 2:
137
+ pub = encbuf.slice(0, 33)
138
+ break
139
+ default:
140
+ throw new Error('Invalid type: ' + encbuf[0])
141
+ }
142
+ this._publicKey = PublicKey.fromDER(pub)
143
+ offset += pub.length
144
+ }
145
+
146
+ var c = encbuf.slice(offset, encbuf.length - tagLength)
147
+ var d = encbuf.slice(encbuf.length - tagLength, encbuf.length)
148
+
149
+ var d2 = Hash.sha256hmac(c, this.kM)
150
+ if (this.opts.shortTag) d2 = d2.slice(0, 4)
151
+
152
+ var equal = true
153
+ for (var i = 0; i < d.length; i++) {
154
+ equal &= (d[i] === d2[i])
155
+ }
156
+ if (!equal) {
157
+ throw new Error('Invalid checksum')
158
+ }
159
+
160
+ return AESCBC.decrypt(c, this.kE)
161
+ }
162
+
163
+ module.exports = ECIES