@bsv/sdk 1.1.22 → 1.1.23

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 (44) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/compat/BSM.js +10 -3
  3. package/dist/cjs/src/compat/BSM.js.map +1 -1
  4. package/dist/cjs/src/primitives/utils.js +39 -1
  5. package/dist/cjs/src/primitives/utils.js.map +1 -1
  6. package/dist/cjs/src/script/Spend.js +2 -39
  7. package/dist/cjs/src/script/Spend.js.map +1 -1
  8. package/dist/cjs/src/script/templates/P2PKH.js +2 -2
  9. package/dist/cjs/src/script/templates/P2PKH.js.map +1 -1
  10. package/dist/cjs/src/script/templates/RPuzzle.js +2 -2
  11. package/dist/cjs/src/script/templates/RPuzzle.js.map +1 -1
  12. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  13. package/dist/esm/src/compat/BSM.js +10 -3
  14. package/dist/esm/src/compat/BSM.js.map +1 -1
  15. package/dist/esm/src/primitives/utils.js +37 -0
  16. package/dist/esm/src/primitives/utils.js.map +1 -1
  17. package/dist/esm/src/script/Spend.js +1 -38
  18. package/dist/esm/src/script/Spend.js.map +1 -1
  19. package/dist/esm/src/script/templates/P2PKH.js +2 -2
  20. package/dist/esm/src/script/templates/P2PKH.js.map +1 -1
  21. package/dist/esm/src/script/templates/RPuzzle.js +2 -2
  22. package/dist/esm/src/script/templates/RPuzzle.js.map +1 -1
  23. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  24. package/dist/types/src/compat/BSM.d.ts +3 -2
  25. package/dist/types/src/compat/BSM.d.ts.map +1 -1
  26. package/dist/types/src/primitives/utils.d.ts +1 -0
  27. package/dist/types/src/primitives/utils.d.ts.map +1 -1
  28. package/dist/types/src/script/Spend.d.ts.map +1 -1
  29. package/dist/types/src/script/templates/P2PKH.d.ts +1 -1
  30. package/dist/types/src/script/templates/P2PKH.d.ts.map +1 -1
  31. package/dist/types/src/script/templates/RPuzzle.d.ts +1 -1
  32. package/dist/types/src/script/templates/RPuzzle.d.ts.map +1 -1
  33. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  34. package/docs/compat.md +10 -4
  35. package/docs/primitives.md +44 -9
  36. package/docs/script.md +4 -4
  37. package/docs/transaction.md +1 -0
  38. package/package.json +1 -1
  39. package/src/compat/BSM.ts +10 -3
  40. package/src/compat/__tests/BSM.test.ts +7 -2
  41. package/src/primitives/utils.ts +43 -0
  42. package/src/script/Spend.ts +1 -44
  43. package/src/script/templates/P2PKH.ts +7 -7
  44. package/src/script/templates/RPuzzle.ts +8 -8
package/src/compat/BSM.ts CHANGED
@@ -30,11 +30,18 @@ export const magicHash = (messageBuf: number[]): number[] => {
30
30
  * @deprecated Replaced by BRC-77 which employs BRC-42 key derivation and BRC-43 invoice numbers for enhanced security and privacy.
31
31
  * @param message The message to be signed as a number array.
32
32
  * @param privateKey The private key used for signing the message.
33
- * @returns The signature object.
33
+ * @param mode The mode of operation. When "base64", the BSM format signature is returned. When "raw", a Signature object is returned. Default: "base64".
34
+ * @returns The signature object when in raw mode, or the BSM base64 string when in base64 mode.
34
35
  */
35
- export const sign = (message: number[], privateKey: PrivateKey): Signature => {
36
+ export const sign = (message: number[], privateKey: PrivateKey, mode: 'raw' | 'base64' = 'base64'): Signature | string => {
36
37
  const hashBuf = magicHash(message)
37
- return ECDSA.sign(new BigNumber(hashBuf), privateKey, true)
38
+ const sig = ECDSA.sign(new BigNumber(hashBuf), privateKey, true)
39
+ if (mode === 'raw') {
40
+ return sig
41
+ }
42
+ const h = new BigNumber(hashBuf)
43
+ const r = sig.CalculateRecoveryFactor(privateKey.toPublicKey(), h)
44
+ return sig.toCompact(r, true, 'base64') as string
38
45
  }
39
46
 
40
47
  /**
@@ -17,16 +17,21 @@ describe('BSM', () => {
17
17
  const messageBuf = toArray('this is my message', 'utf8')
18
18
  const privateKey = new PrivateKey(42)
19
19
  it('should return a signature', () => {
20
- const sig = sign(messageBuf, privateKey).toDER()
20
+ const sig = sign(messageBuf, privateKey, 'raw').toDER()
21
21
  expect(sig.length).toEqual(70)
22
22
  })
23
+ it('Creates the correct base64 signature', () => {
24
+ const privateKey = PrivateKey.fromWif("L211enC224G1kV8pyyq7bjVd9SxZebnRYEzzM3i7ZHCc1c5E7dQu")
25
+ const sig = sign(toArray('hello world', 'utf8'), privateKey, 'base64')
26
+ expect(sig).toEqual('H4T8Asr0WkC6wYfBESR6pCAfECtdsPM4fwiSQ2qndFi8dVtv/mrOFaySx9xQE7j24ugoJ4iGnsRwAC8QwaoHOXk=')
27
+ })
23
28
  })
24
29
  describe('verify', () => {
25
30
  const messageBuf = toArray('this is my message', 'utf8')
26
31
  const privateKey = new PrivateKey(42)
27
32
 
28
33
  it('should verify a signed message', () => {
29
- const sig = sign(messageBuf, privateKey)
34
+ const sig = sign(messageBuf, privateKey, 'raw')
30
35
  expect(verify(messageBuf, sig, privateKey.toPublicKey())).toEqual(true)
31
36
  })
32
37
  it('Should verify a signed message in base64', () => {
@@ -662,3 +662,46 @@ export class Reader {
662
662
  }
663
663
  }
664
664
  }
665
+
666
+ export const minimallyEncode = (buf: number[]): number[] => {
667
+ if (buf.length === 0) {
668
+ return buf
669
+ }
670
+
671
+ // If the last byte is not 0x00 or 0x80, we are minimally encoded.
672
+ const last = buf[buf.length - 1]
673
+ if ((last & 0x7f) !== 0) {
674
+ return buf
675
+ }
676
+
677
+ // If the script is one byte long, then we have a zero, which encodes as an
678
+ // empty array.
679
+ if (buf.length === 1) {
680
+ return []
681
+ }
682
+
683
+ // If the next byte has it sign bit set, then we are minimaly encoded.
684
+ if ((buf[buf.length - 2] & 0x80) !== 0) {
685
+ return buf
686
+ }
687
+
688
+ // We are not minimally encoded, we need to figure out how much to trim.
689
+ for (let i = buf.length - 1; i > 0; i--) {
690
+ // We found a non zero byte, time to encode.
691
+ if (buf[i - 1] !== 0) {
692
+ if ((buf[i - 1] & 0x80) !== 0) {
693
+ // We found a byte with it sign bit set so we need one more
694
+ // byte.
695
+ buf[i++] = last
696
+ } else {
697
+ // the sign bit is clear, we can use it.
698
+ buf[i - 1] |= last
699
+ }
700
+
701
+ return buf.slice(0, i)
702
+ }
703
+ }
704
+
705
+ // If we found the whole thing is zeros, then we have a zero.
706
+ return []
707
+ }
@@ -4,7 +4,7 @@ import Script from './Script.js'
4
4
  import BigNumber from '../primitives/BigNumber.js'
5
5
  import OP from './OP.js'
6
6
  import ScriptChunk from './ScriptChunk.js'
7
- import { toHex } from '../primitives/utils.js'
7
+ import { toHex, minimallyEncode } from '../primitives/utils.js'
8
8
  import * as Hash from '../primitives/Hash.js'
9
9
  import TransactionSignature from '../primitives/TransactionSignature.js'
10
10
  import PublicKey from '../primitives/PublicKey.js'
@@ -206,49 +206,6 @@ export default class Spend {
206
206
  return true
207
207
  }
208
208
 
209
- const minimallyEncode = (buf: number[]): number[] => {
210
- if (buf.length === 0) {
211
- return buf
212
- }
213
-
214
- // If the last byte is not 0x00 or 0x80, we are minimally encoded.
215
- const last = buf[buf.length - 1]
216
- if ((last & 0x7f) !== 0) {
217
- return buf
218
- }
219
-
220
- // If the script is one byte long, then we have a zero, which encodes as an
221
- // empty array.
222
- if (buf.length === 1) {
223
- return []
224
- }
225
-
226
- // If the next byte has it sign bit set, then we are minimaly encoded.
227
- if ((buf[buf.length - 2] & 0x80) !== 0) {
228
- return buf
229
- }
230
-
231
- // We are not minimally encoded, we need to figure out how much to trim.
232
- for (let i = buf.length - 1; i > 0; i--) {
233
- // We found a non zero byte, time to encode.
234
- if (buf[i - 1] !== 0) {
235
- if ((buf[i - 1] & 0x80) !== 0) {
236
- // We found a byte with it sign bit set so we need one more
237
- // byte.
238
- buf[i++] = last
239
- } else {
240
- // the sign bit is clear, we can use it.
241
- buf[i - 1] |= last
242
- }
243
-
244
- return buf.slice(0, i)
245
- }
246
- }
247
-
248
- // If we found the whole thing is zeros, then we have a zero.
249
- return []
250
- }
251
-
252
209
  const padDataToSize = (buf: number[], len: number): number[] => {
253
210
  let b = buf
254
211
  while (b.length < len) {
@@ -21,7 +21,7 @@ export default class P2PKH implements ScriptTemplate {
21
21
  * @param {number[] | string} pubkeyhash or address - An array or address representing the public key hash.
22
22
  * @returns {LockingScript} - A P2PKH locking script.
23
23
  */
24
- lock (pubkeyhash: string | number[]): LockingScript {
24
+ lock(pubkeyhash: string | number[]): LockingScript {
25
25
  let data: number[]
26
26
  if (typeof pubkeyhash === 'string') {
27
27
  const hash = fromBase58Check(pubkeyhash)
@@ -54,16 +54,16 @@ export default class P2PKH implements ScriptTemplate {
54
54
  * @param {Script} lockingScript - Optional. The lockinScript. Otherwise the input.sourceTransaction is required.
55
55
  * @returns {Object} - An object containing the `sign` and `estimateLength` functions.
56
56
  */
57
- unlock (
57
+ unlock(
58
58
  privateKey: PrivateKey,
59
59
  signOutputs: 'all' | 'none' | 'single' = 'all',
60
60
  anyoneCanPay: boolean = false,
61
61
  sourceSatoshis?: number,
62
62
  lockingScript?: Script
63
63
  ): {
64
- sign: (tx: Transaction, inputIndex: number) => Promise<UnlockingScript>
65
- estimateLength: () => Promise<106>
66
- } {
64
+ sign: (tx: Transaction, inputIndex: number) => Promise<UnlockingScript>
65
+ estimateLength: () => Promise<108>
66
+ } {
67
67
  return {
68
68
  sign: async (tx: Transaction, inputIndex: number) => {
69
69
  let signatureScope = TransactionSignature.SIGHASH_FORKID
@@ -130,9 +130,9 @@ export default class P2PKH implements ScriptTemplate {
130
130
  ])
131
131
  },
132
132
  estimateLength: async () => {
133
- // public key (1+33) + signature (1+71)
133
+ // public key (1+33) + signature (1+73)
134
134
  // Note: We add 1 to each element's length because of the associated OP_PUSH
135
- return 106
135
+ return 108
136
136
  }
137
137
  }
138
138
  }
@@ -23,7 +23,7 @@ export default class RPuzzle implements ScriptTemplate {
23
23
  *
24
24
  * @param {'raw'|'SHA1'|'SHA256'|'HASH256'|'RIPEMD160'|'HASH160'} type Denotes the type of puzzle to create
25
25
  */
26
- constructor (type: 'raw' | 'SHA1' | 'SHA256' | 'HASH256' | 'RIPEMD160' | 'HASH160' = 'raw') {
26
+ constructor(type: 'raw' | 'SHA1' | 'SHA256' | 'HASH256' | 'RIPEMD160' | 'HASH160' = 'raw') {
27
27
  this.type = type
28
28
  }
29
29
 
@@ -33,7 +33,7 @@ export default class RPuzzle implements ScriptTemplate {
33
33
  * @param {number[]} value - An array representing the R value or its hash.
34
34
  * @returns {LockingScript} - An R puzzle locking script.
35
35
  */
36
- lock (value: number[]): LockingScript {
36
+ lock(value: number[]): LockingScript {
37
37
  const chunks: ScriptChunk[] = [
38
38
  { op: OP.OP_OVER },
39
39
  { op: OP.OP_3 },
@@ -70,15 +70,15 @@ export default class RPuzzle implements ScriptTemplate {
70
70
  * @param {boolean} anyoneCanPay - Flag indicating if the signature allows for other inputs to be added later.
71
71
  * @returns {Object} - An object containing the `sign` and `estimateLength` functions.
72
72
  */
73
- unlock (
73
+ unlock(
74
74
  k: BigNumber,
75
75
  privateKey: PrivateKey,
76
76
  signOutputs: 'all' | 'none' | 'single' = 'all',
77
77
  anyoneCanPay: boolean = false
78
78
  ): {
79
- sign: (tx: Transaction, inputIndex: number) => Promise<UnlockingScript>
80
- estimateLength: () => Promise<106>
81
- } {
79
+ sign: (tx: Transaction, inputIndex: number) => Promise<UnlockingScript>
80
+ estimateLength: () => Promise<108>
81
+ } {
82
82
  return {
83
83
  sign: async (tx: Transaction, inputIndex: number) => {
84
84
  if (typeof privateKey === 'undefined') {
@@ -131,9 +131,9 @@ export default class RPuzzle implements ScriptTemplate {
131
131
  ])
132
132
  },
133
133
  estimateLength: async () => {
134
- // public key (1+33) + signature (1+71)
134
+ // public key (1+33) + signature (1+73)
135
135
  // Note: We add 1 to each element's length because of the associated OP_PUSH
136
- return 106
136
+ return 108
137
137
  }
138
138
  }
139
139
  }