@smartledger/bsv 7.9.0 → 7.10.1

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 (73) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +38 -38
  3. package/bsv-covenant.min.js +1 -1
  4. package/bsv-ecies.min.js +1 -1
  5. package/bsv-gdaf.min.js +54 -54
  6. package/bsv-ltp.min.js +58 -85
  7. package/bsv-message.min.js +2 -2
  8. package/bsv-mnemonic.min.js +12 -14
  9. package/bsv-script-helper.min.js +1 -1
  10. package/bsv-shamir.min.js +14 -16
  11. package/bsv-smartcontract.min.js +23 -25
  12. package/bsv.bundle.js +54 -54
  13. package/bsv.min.js +54 -54
  14. package/build/esbuild.js +86 -5
  15. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  16. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  17. package/docs/getting-started/INSTALLATION.md +23 -23
  18. package/docs/getting-started/QUICK_START.md +7 -7
  19. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  20. package/index.js +9 -1
  21. package/lib/covenant/helpers.js +146 -0
  22. package/lib/covenant/index.js +21 -0
  23. package/lib/covenant/pushtx.js +243 -0
  24. package/lib/covenant-interface.js +418 -397
  25. package/lib/custom-script-helper.js +44 -38
  26. package/lib/ecies/bitcore-ecies.js +3 -4
  27. package/lib/ecies/electrum-ecies.js +4 -6
  28. package/lib/ecies/errors.js +1 -1
  29. package/lib/gdaf/attestation-signer.js +7 -7
  30. package/lib/gdaf/attestation-verifier.js +5 -6
  31. package/lib/gdaf/did-resolver.js +10 -9
  32. package/lib/gdaf/smartledger-anchor.js +13 -12
  33. package/lib/gdaf/zk-prover.js +8 -8
  34. package/lib/ltp/anchor.js +2 -3
  35. package/lib/ltp/claim.js +2 -3
  36. package/lib/ltp/index.js +2 -3
  37. package/lib/ltp/obligation.js +9 -9
  38. package/lib/ltp/proof.js +7 -7
  39. package/lib/ltp/registry.js +4 -5
  40. package/lib/ltp/right.js +11 -11
  41. package/lib/message/index.js +5 -4
  42. package/lib/message/message.js +11 -11
  43. package/lib/mnemonic/errors.js +1 -1
  44. package/lib/mnemonic/index.js +5 -4
  45. package/lib/mnemonic/mnemonic.js +22 -10
  46. package/lib/ordinals/bsv20.js +4 -4
  47. package/lib/ordinals/inscription.js +8 -12
  48. package/lib/ordinals/ordlock.js +26 -21
  49. package/lib/smart_contract/authorizers.js +8 -6
  50. package/lib/smart_contract/builder.js +32 -26
  51. package/lib/smart_contract/covenant.js +32 -25
  52. package/lib/smart_contract/covenant_helpers.js +8 -139
  53. package/lib/smart_contract/debugger.js +9 -6
  54. package/lib/smart_contract/dsl.js +5 -6
  55. package/lib/smart_contract/index.js +11 -8
  56. package/lib/smart_contract/locks.js +3 -4
  57. package/lib/smart_contract/opcode_list.js +2 -3
  58. package/lib/smart_contract/pels.js +4 -5
  59. package/lib/smart_contract/preimage.js +11 -7
  60. package/lib/smart_contract/pushtx.js +8 -263
  61. package/lib/smart_contract/script_interpreter.js +112 -105
  62. package/lib/smart_contract/script_tester.js +24 -18
  63. package/lib/smart_contract/script_utils.js +15 -14
  64. package/lib/smart_contract/sighash.js +23 -15
  65. package/lib/smart_contract/stack_examiner.js +70 -63
  66. package/lib/smart_contract/token.js +6 -6
  67. package/lib/smart_contract/utxo_generator.js +21 -15
  68. package/lib/smartutxo.js +27 -21
  69. package/lib/spv/headerchain.js +3 -3
  70. package/lib/spv/merkleproof.js +3 -3
  71. package/package.json +4 -2
  72. package/test/build/bundle_externals.js +116 -0
  73. package/version.js +1 -1
@@ -1,140 +1,9 @@
1
1
  'use strict'
2
- /**
3
- * SmartContract covenant helpers
4
- * ==============================
5
- *
6
- * Shared utilities for building and verifying custom locking scripts &
7
- * OP_PUSH_TX covenants: a consensus-flag verify() harness, raw BIP-143 preimage
8
- * access, signing, and fund/spend scaffolding. Used by ./pushtx, ./pels, ./token
9
- * and ./locks.
10
- */
11
-
12
- var bsv = require('../..')
13
- var BN = require('../crypto/bn')
14
- var Hash = require('../crypto/hash')
15
- var Signature = require('../crypto/signature')
16
-
17
- // SIGHASH_ALL | SIGHASH_FORKID — the BSV default these covenants are built for.
18
- var SIGHASH = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID // 0x41
19
-
20
- // Post-Genesis consensus + STANDARD RELAY flags — what mainnet miners actually
21
- // enforce. Includes SCRIPT_VERIFY_MINIMALDATA (every push must be minimal) and
22
- // SCRIPT_VERIFY_LOW_S (canonical signatures). Verifying with these flags locally
23
- // mirrors mainnet relay/consensus policy, so a covenant that passes here is
24
- // expected to be accepted on broadcast — catch non-relayable scripts before then.
25
- function flags () {
26
- var I = bsv.Script.Interpreter
27
- return I.SCRIPT_VERIFY_P2SH |
28
- I.SCRIPT_VERIFY_STRICTENC |
29
- I.SCRIPT_VERIFY_DERSIG |
30
- I.SCRIPT_VERIFY_LOW_S |
31
- I.SCRIPT_VERIFY_MINIMALDATA |
32
- I.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
33
- I.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
34
- I.SCRIPT_ENABLE_SIGHASH_FORKID |
35
- I.SCRIPT_ENABLE_MAGNETIC_OPCODES |
36
- I.SCRIPT_ENABLE_MONOLITH_OPCODES |
37
- // REQUIRED, not optional. pushTxCore emits OP_RIGHT/OP_LEFT — see
38
- // extractHashOutputs and assertSighashType — and those bytes (180/181) are
39
- // upgradable NOPs on the network until Chronicle activates. Without this
40
- // flag the interpreter treats them as no-ops, exactly as a pre-Chronicle
41
- // node does, and the covenant does not verify.
42
- //
43
- // Stated plainly: OP_PUSH_TX covenants built by this library DEPEND on
44
- // Chronicle and cannot be spent on a pre-Chronicle chain. That was
45
- // previously invisible because the interpreter ran the string opcodes
46
- // unconditionally — more permissively than the network.
47
- I.SCRIPT_ENABLE_CHRONICLE
48
- }
49
-
50
- /**
51
- * Opt into post-Genesis script limits (needed by OP_PUSH_TX covenants).
52
- * Thin wrapper over Interpreter.useGenesisLimits (added in 4.1.0).
53
- */
54
- function enableGenesis (max) {
55
- return bsv.Script.Interpreter.useGenesisLimits(max)
56
- }
57
-
58
- /**
59
- * Verify an unlocking script against a locking script through the consensus
60
- * interpreter. @returns {{ok:boolean, err:string}}
61
- */
62
- function verify (unlockingScript, lockingScript, opts) {
63
- opts = opts || {}
64
- var interp = new bsv.Script.Interpreter()
65
- var ok = interp.verify(
66
- unlockingScript,
67
- lockingScript,
68
- opts.tx || new bsv.Transaction(),
69
- opts.inputIndex || 0,
70
- opts.flags || flags(),
71
- new BN(opts.satoshis || 0)
72
- )
73
- return { ok: ok, err: interp.errstr || '' }
74
- }
75
-
76
- /** Raw BIP-143 preimage (the serialization that is double-SHA256'd), not the digest. */
77
- function rawPreimage (tx, inputIndex, lockingScript, satoshis, sighashType) {
78
- return bsv.Transaction.sighash.sighashPreimage(
79
- tx, sighashType || SIGHASH, inputIndex, lockingScript, new BN(satoshis))
80
- }
81
-
82
- /** Sighash digest = HASH256(rawPreimage) — useful for asserting OP_PUSH_TX linkage in JS. */
83
- function sighashDigest (tx, inputIndex, lockingScript, satoshis, sighashType) {
84
- return Hash.sha256sha256(rawPreimage(tx, inputIndex, lockingScript, satoshis, sighashType))
85
- }
86
-
87
- /** DER+sighash-byte signature over `lockingScript` for `inputIndex`. */
88
- function signInput (tx, privateKey, inputIndex, lockingScript, satoshis, sighashType) {
89
- sighashType = sighashType || SIGHASH
90
- var sig = bsv.Transaction.sighash.sign(tx, privateKey, sighashType, inputIndex, lockingScript, new BN(satoshis))
91
- return Buffer.concat([sig.toDER(), Buffer.from([sighashType])])
92
- }
93
-
94
- /**
95
- * Build a funding tx paying `satoshis` into `lockingScript`, plus a spending tx
96
- * consuming it with the supplied outputs. Returns { funding, spend }; the caller
97
- * sets spend.inputs[0] script.
98
- */
99
- function fundAndSpend (lockingScript, satoshis, opts) {
100
- opts = opts || {}
101
- var funding = new bsv.Transaction().addOutput(
102
- new bsv.Transaction.Output({ script: lockingScript, satoshis: satoshis }))
103
- var spend = new bsv.Transaction()
104
- spend.addInput(
105
- new bsv.Transaction.Input({ prevTxId: funding.hash, outputIndex: 0, script: bsv.Script.empty() }),
106
- lockingScript, satoshis)
107
- if (opts.outputs) opts.outputs.forEach(function (o) { spend.addOutput(o) })
108
- return { funding: funding, spend: spend }
109
- }
110
-
111
- /** A P2PKH Output object for an address or public key. */
112
- function p2pkhOutput (addressOrPubKey, satoshis) {
113
- var addr = addressOrPubKey.toAddress ? addressOrPubKey.toAddress() : addressOrPubKey
114
- return new bsv.Transaction.Output({ script: bsv.Script.buildPublicKeyHashOut(addr), satoshis: satoshis })
115
- }
116
-
117
- /** Minimal little-endian script-number Buffer (push as data to put a number on-stack). */
118
- function scriptNum (n) {
119
- // Minimal on-stack number: 0..16 and -1 use the dedicated opcodes (OP_0..OP_16,
120
- // OP_1NEGATE) instead of a data push, so covenant scripts stay MINIMALDATA-clean
121
- // (mainnet relay policy). Larger values use a minimal scriptNum push. The result
122
- // is passed to Script.add(), which accepts an opcode number or a Buffer.
123
- if (n === 0) return bsv.Opcode.OP_0
124
- if (n === -1) return bsv.Opcode.OP_1NEGATE
125
- if (n >= 1 && n <= 16) return bsv.Opcode['OP_' + n]
126
- return new BN(n).toScriptNumBuffer()
127
- }
128
-
129
- module.exports = {
130
- SIGHASH: SIGHASH,
131
- flags: flags,
132
- enableGenesis: enableGenesis,
133
- verify: verify,
134
- rawPreimage: rawPreimage,
135
- sighashDigest: sighashDigest,
136
- signInput: signInput,
137
- fundAndSpend: fundAndSpend,
138
- p2pkhOutput: p2pkhOutput,
139
- scriptNum: scriptNum
140
- }
2
+ // Moved to lib/covenant/helpers.js.
3
+ //
4
+ // lib/ordinals needs these primitives too, and importing them from
5
+ // lib/smart_contract was the only dependency from core code into the
6
+ // application layer. This path is retained because deep imports
7
+ // (require('@smartledger/bsv/lib/smart_contract/covenant_helpers')) are public
8
+ // API via the package.json exports map.
9
+ module.exports = require('../covenant/helpers')
@@ -9,8 +9,11 @@
9
9
  * covenants (their preimage element / opcode count exceed pre-Genesis limits).
10
10
  */
11
11
 
12
- var bsv = require('../..')
13
- var helpers = require('./covenant_helpers')
12
+ var Interpreter = require('../script/interpreter')
13
+ var BN = require('../crypto/bn')
14
+ var Transaction = require('../transaction')
15
+ var Opcode = require('../opcode')
16
+ var helpers = require('../covenant/helpers')
14
17
 
15
18
  function opLabel (opcodenum) {
16
19
  if (opcodenum === 0) return 'OP_0'
@@ -18,7 +21,7 @@ function opLabel (opcodenum) {
18
21
  if (opcodenum === 76) return 'OP_PUSHDATA1'
19
22
  if (opcodenum === 77) return 'OP_PUSHDATA2'
20
23
  if (opcodenum === 78) return 'OP_PUSHDATA4'
21
- try { return bsv.Opcode.fromNumber(opcodenum).toString() } catch (e) { return '0x' + opcodenum.toString(16) }
24
+ try { return Opcode.fromNumber(opcodenum).toString() } catch (e) { return '0x' + opcodenum.toString(16) }
22
25
  }
23
26
 
24
27
  function hex (buf, max) {
@@ -32,7 +35,7 @@ function hex (buf, max) {
32
35
  */
33
36
  function trace (unlock, lock, opts) {
34
37
  opts = opts || {}
35
- var interp = new bsv.Script.Interpreter()
38
+ var interp = new Interpreter()
36
39
  var steps = []
37
40
  interp.stepListener = function (step, stack, altstack) {
38
41
  steps.push({
@@ -44,10 +47,10 @@ function trace (unlock, lock, opts) {
44
47
  }
45
48
  var ok = interp.verify(
46
49
  unlock, lock,
47
- opts.tx || new bsv.Transaction(),
50
+ opts.tx || new Transaction(),
48
51
  opts.inputIndex || 0,
49
52
  typeof opts.flags === 'number' ? opts.flags : helpers.flags(),
50
- new bsv.crypto.BN(opts.satoshis || 0)
53
+ new BN(opts.satoshis || 0)
51
54
  )
52
55
  return { ok: ok, err: interp.errstr || '', steps: steps }
53
56
  }
@@ -18,15 +18,14 @@
18
18
  * time (SmartContract.enableGenesis()).
19
19
  */
20
20
 
21
- var bsv = require('../..')
22
- var PushTx = require('./pushtx')
21
+ var PushTx = require('../covenant/pushtx')
23
22
  var PELS = require('./pels')
24
23
  var Token = require('./token')
25
- var helpers = require('./covenant_helpers')
24
+ var helpers = require('../covenant/helpers')
26
25
 
27
- var Script = bsv.Script
28
- var Opcode = bsv.Opcode
29
- var Transaction = bsv.Transaction
26
+ var Script = require('../script')
27
+ var Opcode = require('../opcode')
28
+ var Transaction = require('../transaction')
30
29
  var n = helpers.scriptNum
31
30
 
32
31
  function toOutput (dest, satoshis) {
@@ -27,7 +27,10 @@
27
27
 
28
28
  'use strict'
29
29
 
30
- var bsv = require('../..')
30
+ var Hash = require('../crypto/hash')
31
+ var Transaction = require('../transaction')
32
+ var Address = require('../address')
33
+ var Script = require('../script')
31
34
 
32
35
  var SmartContract = {
33
36
  Covenant: require('./covenant'),
@@ -44,9 +47,9 @@ var SmartContract = {
44
47
  ScriptInterpreter: require('./script_interpreter'),
45
48
 
46
49
  // Interpreter-verified custom locking scripts & OP_PUSH_TX covenants (v4.2.0)
47
- CovenantHelpers: require('./covenant_helpers'),
50
+ CovenantHelpers: require('../covenant/helpers'),
48
51
  Locks: require('./locks'),
49
- PushTx: require('./pushtx'),
52
+ PushTx: require('../covenant/pushtx'),
50
53
  PELS: require('./pels'),
51
54
  Token: require('./token'),
52
55
  Authorizers: require('./authorizers'),
@@ -258,14 +261,14 @@ SmartContract.debugScriptExecution = function (unlockingScript, lockingScript, o
258
261
  if (options.stepMode) {
259
262
  return SmartContract.ScriptInterpreter.stepThroughScript(
260
263
  SmartContract.ScriptInterpreter.parseScript(unlockingScript + ' ' + lockingScript),
261
- new bsv.Transaction(),
264
+ new Transaction(),
262
265
  true
263
266
  )
264
267
  } else {
265
268
  return SmartContract.ScriptInterpreter.runFullEvaluation(
266
269
  SmartContract.ScriptInterpreter.parseScript(unlockingScript),
267
270
  SmartContract.ScriptInterpreter.parseScript(lockingScript),
268
- new bsv.Transaction()
271
+ new Transaction()
269
272
  )
270
273
  }
271
274
  }
@@ -362,13 +365,13 @@ SmartContract.getEducationalResources = function () {
362
365
  // Utility functions
363
366
  SmartContract.utils = {}
364
367
  SmartContract.utils.reconstructP2pkhScript = function (address) {
365
- return bsv.Script.buildPublicKeyHashOut(address).toHex()
368
+ return Script.buildPublicKeyHashOut(address).toHex()
366
369
  }
367
370
 
368
371
  SmartContract.utils.createCovenantAddress = function (script) {
369
372
  // Create P2SH address for covenant script
370
- var scriptHash = bsv.crypto.Hash.sha256ripemd160(script.toBuffer())
371
- return bsv.Address.fromScriptHash(scriptHash)
373
+ var scriptHash = Hash.sha256ripemd160(script.toBuffer())
374
+ return Address.fromScriptHash(scriptHash)
372
375
  }
373
376
 
374
377
  SmartContract.utils.decodeCompactSize = function (buffer, offset) {
@@ -4,12 +4,11 @@
4
4
  * Each factory returns { lock: Script, unlock: fn, meta }.
5
5
  */
6
6
 
7
- var bsv = require('../..')
8
7
  var Hash = require('../crypto/hash')
9
- var H = require('./covenant_helpers')
8
+ var H = require('../covenant/helpers')
10
9
 
11
- var Script = bsv.Script
12
- var Opcode = bsv.Opcode
10
+ var Script = require('../script')
11
+ var Opcode = require('../opcode')
13
12
  var signInput = H.signInput
14
13
  var n = H.scriptNum
15
14
 
@@ -1,12 +1,11 @@
1
- const bsv = require('../..')
2
- const opcode = bsv.Opcode;
1
+ const opcode = require('../opcode')
3
2
  console.log('Opcode List:');
4
3
  for (let key in opcode.map) {
5
4
  const code = opcode.map[key];
6
5
  console.log(`${key}: 0x${code.toString(16).padStart(2, '0')}`);
7
6
  }
8
7
 
9
- const Script = bsv.Script;
8
+ const Script = require('../script')
10
9
  console.log(Script);
11
10
  console.log('\nSample Script using OP_CHECKSIG and OP_RETURN:');
12
11
  const script = new Script()
@@ -17,12 +17,11 @@
17
17
  * Requires post-Genesis limits (SmartContract.enableGenesis()).
18
18
  */
19
19
 
20
- var bsv = require('../..')
21
- var P = require('./pushtx')
22
- var H = require('./covenant_helpers')
20
+ var P = require('../covenant/pushtx')
21
+ var H = require('../covenant/helpers')
23
22
 
24
- var Script = bsv.Script
25
- var Opcode = bsv.Opcode
23
+ var Script = require('../script')
24
+ var Opcode = require('../opcode')
26
25
  var n = H.scriptNum
27
26
 
28
27
  /**
@@ -13,7 +13,11 @@
13
13
 
14
14
  'use strict'
15
15
 
16
- var bsv = require('../..')
16
+ var sighash = require('../transaction/sighash')
17
+ var BN = require('../crypto/bn')
18
+ var Transaction = require('../transaction')
19
+ var PrivateKey = require('../privatekey')
20
+ var Script = require('../script')
17
21
  var crypto = require('crypto')
18
22
 
19
23
  /**
@@ -800,12 +804,12 @@ Preimage.decodeCompactSize = function(buffer, offset) {
800
804
  * @returns {Preimage} Preimage instance
801
805
  */
802
806
  Preimage.fromTransaction = function(transaction, inputIndex, subscript, satoshis, sighashType) {
803
- var preimageBuffer = bsv.Transaction.sighash.sighashPreimage(
807
+ var preimageBuffer = sighash.sighashPreimage(
804
808
  transaction,
805
809
  sighashType,
806
810
  inputIndex,
807
811
  subscript,
808
- new bsv.crypto.BN(satoshis)
812
+ new BN(satoshis)
809
813
  )
810
814
 
811
815
  return new Preimage(preimageBuffer, {
@@ -824,21 +828,21 @@ Preimage.fromTransaction = function(transaction, inputIndex, subscript, satoshis
824
828
  */
825
829
  Preimage.createExample = function(sighashType) {
826
830
  // Create a simple example transaction
827
- var privateKey = bsv.PrivateKey.fromRandom()
831
+ var privateKey = PrivateKey.fromRandom()
828
832
  var address = privateKey.toAddress()
829
833
 
830
834
  var utxo = {
831
835
  txId: '0'.repeat(64),
832
836
  outputIndex: 0,
833
- script: bsv.Script.buildPublicKeyHashOut(address).toHex(),
837
+ script: Script.buildPublicKeyHashOut(address).toHex(),
834
838
  satoshis: 100000
835
839
  }
836
840
 
837
- var transaction = new bsv.Transaction()
841
+ var transaction = new Transaction()
838
842
  .from(utxo)
839
843
  .to(address, 99000)
840
844
 
841
- var subscript = bsv.Script.fromHex(utxo.script)
845
+ var subscript = Script.fromHex(utxo.script)
842
846
 
843
847
  return Preimage.fromTransaction(transaction, 0, subscript, utxo.satoshis, sighashType)
844
848
  }
@@ -1,264 +1,9 @@
1
1
  'use strict'
2
- /**
3
- * SmartContract.PushTx — a correct, interpreter-verified OP_PUSH_TX (nChain
4
- * WP1605) for Bitcoin SV.
5
- *
6
- * The locking script GENERATES an ECDSA signature in-script from a preimage the
7
- * spender pushed, then OP_CHECKSIG verifies it against a fixed public key.
8
- * OP_CHECKSIG only passes if the message it derives internally (the genuine
9
- * BIP-143 sighash of THIS spend) equals HASH256(preimage) — so a passing check
10
- * proves the pushed preimage IS this transaction, letting a script read and
11
- * constrain its own spending transaction.
12
- *
13
- * Optimal parameters: private key a = 1, ephemeral k = 1 => r = Gx,
14
- * s = (e + Gx) mod n, pubkey P = 02||Gx, e = HASH256(preimage).
15
- *
16
- * Requires post-Genesis limits — call SmartContract.enableGenesis() (a.k.a
17
- * Interpreter.useGenesisLimits()) before verifying these scripts.
18
- */
19
-
20
- var bsv = require('../..')
21
- var BN = require('../crypto/bn')
22
- var Hash = require('../crypto/hash')
23
- var H = require('./covenant_helpers')
24
-
25
- var Script = bsv.Script
26
- var Opcode = bsv.Opcode
27
- var SIGHASH = H.SIGHASH
28
- var scriptNum = H.scriptNum
29
-
30
- // secp256k1 constants (big-endian)
31
- var Gx = Buffer.from('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 'hex')
32
- var N = new BN('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16)
33
- var PUBKEY = Buffer.concat([Buffer.from([0x02]), Gx]) // compressed P = G (y even)
34
-
35
- // script-number (little-endian) forms
36
- var gxLe = Buffer.from(Gx).reverse() // 32B, top 0x79 => positive
37
- var N_LE = Buffer.concat([Buffer.from(N.toBuffer()).reverse(), Buffer.from([0x00])]) // 33B positive
38
-
39
- // fixed DER prefix: SEQUENCE(0x44) INTEGER(0x20) r=Gx INTEGER(0x20)
40
- var DER_PREFIX = Buffer.concat([Buffer.from([0x30, 0x44, 0x02, 0x20]), Gx, Buffer.from([0x02, 0x20])])
41
-
42
- /** Reverse a fixed n-byte buffer on top of the stack (big-endian <-> little-endian). */
43
- function reverseBytes (script, n) {
44
- var i
45
- for (i = 0; i < n - 1; i++) script.add(Opcode.OP_1).add(Opcode.OP_SPLIT)
46
- for (i = 0; i < n - 1; i++) script.add(Opcode.OP_SWAP).add(Opcode.OP_CAT)
47
- return script
48
- }
49
-
50
- // Common SIGHASH flag combinations (all include FORKID, required on BSV). The
51
- // marketplace/partially-signed pattern uses SINGLE|ANYONECANPAY: the signer commits
52
- // only to its own input and its own output (the output at the same index), leaving
53
- // a counterparty free to add funding inputs and change outputs without invalidating
54
- // the signature.
55
- var Signature = bsv.crypto.Signature
56
- var SIGHASH_ALL_FORKID = Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID // 0x41
57
- var SIGHASH_SINGLE_FORKID = Signature.SIGHASH_SINGLE | Signature.SIGHASH_FORKID // 0x43
58
- var SIGHASH_SINGLE_ANYONECANPAY_FORKID =
59
- Signature.SIGHASH_SINGLE | Signature.SIGHASH_ANYONECANPAY | Signature.SIGHASH_FORKID // 0xc3
60
- // ALL|ANYONECANPAY commits to ALL outputs (so the covenant can pin the FULL output
61
- // set) while leaving inputs open for a counterparty to add funding. This is the flag
62
- // the 1Sat Ordinals OrdLock uses: the buyer supplies the surrounding outputs and the
63
- // covenant binds the seller's payment output into the committed hashOutputs.
64
- var SIGHASH_ALL_ANYONECANPAY_FORKID =
65
- Signature.SIGHASH_ALL | Signature.SIGHASH_ANYONECANPAY | Signature.SIGHASH_FORKID // 0xc1
66
-
67
- /**
68
- * Append the in-script signature generator + verifier ("PUSH_TX core").
69
- * Pre: top of stack = preimage. Post: top = OP_CHECKSIG result.
70
- *
71
- * @param {Script} script
72
- * @param {object} [opts]
73
- * @param {number} [opts.sighashType=0x41] the SIGHASH flag byte baked into the
74
- * synthetic signature. OP_CHECKSIG derives the spend's sighash using THIS flag,
75
- * so the spender must push the matching BIP-143 preimage (grind with the same
76
- * sighashType). Defaults to SIGHASH_ALL|FORKID — existing covenants are unchanged.
77
- */
78
- function pushTxCore (script, opts) {
79
- var sighashType = (opts && opts.sighashType) || SIGHASH
80
- script.add(Opcode.OP_HASH256) // z = HASH256(preimage), 32B BE
81
- reverseBytes(script, 32) // -> little-endian = e. The grind guarantees e is
82
- // already positive and minimally encoded (z[0] in 0x01..0x7f), so NO 0x00 sign
83
- // byte is appended — keeping the script MINIMALDATA-clean (mainnet-relayable).
84
- script.add(gxLe).add(Opcode.OP_ADD) // e + Gx
85
- script.add(N_LE).add(Opcode.OP_MOD) // s = (e + Gx) mod n
86
- script.add(scriptNum(32)).add(Opcode.OP_NUM2BIN) // s -> 32-byte LE
87
- reverseBytes(script, 32) // -> big-endian (DER INTEGER body) ; stack: [s_be]
88
- // Build the DER signature and the pubkey from a SINGLE Gx push (Gx is both the
89
- // r-value inside the DER prefix and the body of the 02||Gx pubkey). Sharing it
90
- // via the altstack saves a 32-byte constant vs. embedding Gx twice.
91
- script.add(Gx).add(Opcode.OP_DUP) // [s_be, Gx, Gx]
92
- script.add(Opcode.OP_2).add(Opcode.OP_SWAP).add(Opcode.OP_CAT) // pubkey = 02||Gx (OP_2 = minimal push of 0x02)
93
- script.add(Opcode.OP_TOALTSTACK) // park pubkey ; [s_be, Gx]
94
- script.add(Buffer.from([0x30, 0x44, 0x02, 0x20])).add(Opcode.OP_SWAP).add(Opcode.OP_CAT) // 30440220||Gx
95
- script.add(Buffer.from([0x02, 0x20])).add(Opcode.OP_CAT) // ||0220 => DER prefix
96
- script.add(Opcode.OP_SWAP).add(Opcode.OP_CAT) // DER prefix || s_be
97
- script.add(Buffer.from([sighashType])).add(Opcode.OP_CAT) // || sighash flag => full DER sig
98
- script.add(Opcode.OP_FROMALTSTACK).add(Opcode.OP_CHECKSIG) // pubkey ; verify against P = G
99
- return script
100
- }
101
-
102
- /** Bare authenticator script: unlock with the (grindable) preimage. */
103
- function authenticator () {
104
- return pushTxCore(new Script())
105
- }
106
-
107
- /** Extract the committed hashOutputs (item 9, offsetFromEnd 40, len 32) from a preimage on-stack. */
108
- function extractHashOutputs (script) {
109
- // last 40 bytes, then the first 32 of those = hashOutputs. (BSV string opcodes.)
110
- script.add(scriptNum(40)).add(Opcode.OP_RIGHT).add(scriptNum(32)).add(Opcode.OP_LEFT)
111
- return script
112
- }
113
-
114
- // The BIP-143 preimage ends with nHashType as a 4-byte LE word; for SIGHASH_ALL|
115
- // FORKID that word is 0x41 00 00 00. assertSighashType builds this word per flag.
116
-
117
- /**
118
- * Assert the spend is SIGHASH_ALL|FORKID (0x41). Pre/Post: top of stack = preimage
119
- * (left untouched). These covenants read fixed offsets (104 / 52 / 40) that are
120
- * meaningful only for the 0x41 layout, and the OP_PUSH_TX core already pins the
121
- * flag implicitly (its synthetic sig carries 0x41, so OP_CHECKSIG only accepts a
122
- * preimage hashing to the 0x41 sighash). Note the offsets themselves are invariant
123
- * in the number of INPUTS — hashPrevouts/hashSequence are digests of all inputs,
124
- * so the preimage is the same length for 1 or N inputs; the covenant simply does
125
- * not constrain sibling inputs, by design. What it does assume is a single
126
- * recreated OUTPUT (HASH256(nextOutput) == hashOutputs). This guard makes the
127
- * flag assumption explicit and fails fast — and survives any refactor of the core.
128
- */
129
- function assertSighashAll (script) {
130
- return assertSighashType(script, SIGHASH)
131
- }
132
-
133
- /**
134
- * Assert the spend uses a specific SIGHASH flag. Pre/Post: top of stack = preimage
135
- * (left untouched). The BIP-143 preimage's trailing 4-byte LE nHashType word must
136
- * equal `sighashType`. Use with pushTxCore({ sighashType }) + grind({ sighashType })
137
- * to build covenants under SIGHASH_SINGLE|ANYONECANPAY (marketplace) etc.
138
- */
139
- function assertSighashType (script, sighashType) {
140
- var word = Buffer.from([sighashType & 0xff, 0x00, 0x00, 0x00])
141
- script.add(Opcode.OP_DUP).add(scriptNum(4)).add(Opcode.OP_RIGHT)
142
- .add(word).add(Opcode.OP_EQUALVERIFY)
143
- return script
144
- }
145
-
146
- /** BIP-143 hashOutputs (SIGHASH_ALL) for a set of Transaction.Output objects. */
147
- function hashOutputs (outputs) {
148
- var ser = Buffer.concat(outputs.map(function (o) { return o.toBufferWriter().toBuffer() }))
149
- return Hash.sha256sha256(ser)
150
- }
151
-
152
- /**
153
- * Value/output covenant: the spend is valid only if its outputs hash to
154
- * `expectedHashOutputs` — coins can only go where the covenant says.
155
- */
156
- function valueCovenant (expectedHashOutputs) {
157
- var script = new Script().add(Opcode.OP_DUP)
158
- pushTxCore(script)
159
- script.add(Opcode.OP_VERIFY)
160
- extractHashOutputs(script)
161
- script.add(Buffer.from(expectedHashOutputs)).add(Opcode.OP_EQUAL)
162
- return script
163
- }
164
-
165
- // floor(n/2) — the canonical low-S boundary (matches Signature.hasLowS()).
166
- var HALF_N = new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex')
167
-
168
- /**
169
- * Compute s = (HASH256(preimage)+Gx) mod n; return its 32-byte BE form, or null
170
- * if the resulting signature would not be a clean, CANONICAL (low-S) DER.
171
- * Requiring s <= n/2 makes the in-script signature non-malleable and standard,
172
- * so it passes nodes enforcing SCRIPT_VERIFY_LOW_S — at zero script-size cost
173
- * (the burden is on the spender's grind, not extra opcodes).
174
- */
175
- function sFromPreimage (preimage) {
176
- var z = Hash.sha256sha256(preimage)
177
- // Script no longer sign-extends z, so e (= reverse(z) as a number) must be
178
- // positive AND minimally encoded: its little-endian MSB (= z[0]) in 0x01..0x7f.
179
- // This keeps the locking script MINIMALDATA-clean (mainnet-relayable).
180
- if (z[0] < 0x01 || z[0] > 0x7f) return null
181
- var s = new BN(z).add(new BN(Gx)).mod(N)
182
- if (s.gt(HALF_N)) return null // enforce low-S (canonical / non-malleable)
183
- // NOT s.toBuffer('be', 32): lib/crypto/bn.js REPLACES toBuffer with an
184
- // options-object form, so 'be' would land in `opts`, opts.size would be
185
- // undefined and the 32 ignored — yielding a natural-length buffer.
186
- //
187
- // That truncation is currently UNREACHABLE, and the reason is worth writing
188
- // down because it is not obvious: z is filtered to a leading byte of
189
- // 0x01..0x7f above, so z is in [2**248, 2**255); adding Gx (~0.476 * 2**256)
190
- // never wraps; and the low-S check caps the result at n/2. s therefore lands
191
- // in a narrow band with a leading byte of 0x7a..0x7f and is always 32 bytes.
192
- //
193
- // The call is still wrong, and worth fixing, because that safety is an
194
- // accident of two filters that have nothing to do with buffer length. Widen
195
- // the MINIMALDATA range or drop low-S and the truncation becomes reachable —
196
- // silently, inside a covenant, where DER_PREFIX declares s to be exactly 32
197
- // bytes and a short one makes the spend invalid.
198
- var sBE = s.toBuffer({ size: 32 })
199
- return (sBE[0] >= 0x01) ? sBE : null // s <= n/2 already guarantees sBE[0] <= 0x7f
200
- }
201
-
202
- /**
203
- * Grind a malleable field of the spend until the in-script OP_PUSH_TX signature
204
- * is a clean, canonical (low-S) fixed-length DER. Returns { preimage, tries,
205
- * field, nonce }; mutates the chosen field on `spend`.
206
- *
207
- * @param {object} [opts] grind options (a bare number is accepted as legacy maxTries):
208
- * - maxTries {number} attempts before giving up (default 5000).
209
- * - start {number} first nonce value to try (default 0).
210
- * - field {'nLockTime'|'sequence'} which field carries the grind nonce
211
- * (default 'nLockTime'). Use 'sequence' when the covenant pins nLockTime for
212
- * a real CLTV absolute timelock: the input's sequence is swept down from
213
- * 0xfffffffe (kept non-final, so CLTV still triggers) instead of clobbering
214
- * nLockTime. (Not for CSV/relative-locktime covenants, which encode meaning
215
- * in the sequence number itself.)
216
- */
217
- function grind (spend, inputIndex, lockingScript, satoshis, opts) {
218
- if (typeof opts === 'number') opts = { maxTries: opts } // back-compat: legacy maxTries arg
219
- opts = opts || {}
220
- var maxTries = opts.maxTries || 5000
221
- var start = opts.start || 0
222
- var field = opts.field || 'nLockTime'
223
- var sighashType = opts.sighashType || SIGHASH
224
- if (field !== 'nLockTime' && field !== 'sequence') {
225
- throw new Error("grind field must be 'nLockTime' or 'sequence'")
226
- }
227
- var input = spend.inputs[inputIndex]
228
- for (var i = 0; i < maxTries; i++) {
229
- var nonce = start + i
230
- if (field === 'nLockTime') spend.nLockTime = nonce
231
- else input.sequenceNumber = 0xfffffffe - nonce // stay < 0xffffffff (non-final)
232
- var preimage = H.rawPreimage(spend, inputIndex, lockingScript, satoshis, sighashType)
233
- // Length-checked, not truthy: grind's contract is a FIXED-length DER
234
- // signature, and a short s would be truthy. Belt-and-braces alongside the
235
- // toBuffer fix above — this is the check that would catch it if the
236
- // upstream filters that currently make a short s impossible ever change.
237
- var sBE = sFromPreimage(preimage)
238
- if (sBE && sBE.length === 32) return { preimage: preimage, tries: i + 1, field: field, nonce: nonce }
239
- }
240
- throw new Error('OP_PUSH_TX grind failed after ' + maxTries + ' tries')
241
- }
242
-
243
- module.exports = {
244
- Gx: Gx,
245
- N: N,
246
- PUBKEY: PUBKEY,
247
- gxLe: gxLe,
248
- N_LE: N_LE,
249
- DER_PREFIX: DER_PREFIX,
250
- reverseBytes: reverseBytes,
251
- pushTxCore: pushTxCore,
252
- authenticator: authenticator,
253
- extractHashOutputs: extractHashOutputs,
254
- assertSighashAll: assertSighashAll,
255
- assertSighashType: assertSighashType,
256
- SIGHASH_ALL_FORKID: SIGHASH_ALL_FORKID,
257
- SIGHASH_SINGLE_FORKID: SIGHASH_SINGLE_FORKID,
258
- SIGHASH_SINGLE_ANYONECANPAY_FORKID: SIGHASH_SINGLE_ANYONECANPAY_FORKID,
259
- SIGHASH_ALL_ANYONECANPAY_FORKID: SIGHASH_ALL_ANYONECANPAY_FORKID,
260
- hashOutputs: hashOutputs,
261
- valueCovenant: valueCovenant,
262
- sFromPreimage: sFromPreimage,
263
- grind: grind
264
- }
2
+ // Moved to lib/covenant/pushtx.js.
3
+ //
4
+ // lib/ordinals needs these primitives too, and importing them from
5
+ // lib/smart_contract was the only dependency from core code into the
6
+ // application layer. This path is retained because deep imports
7
+ // (require('@smartledger/bsv/lib/smart_contract/pushtx')) are public API via
8
+ // the package.json exports map.
9
+ module.exports = require('../covenant/pushtx')