Commit Graph

269 Commits

Author SHA1 Message Date
Olaoluwa Osuntokun
99e4e00345
txscript: add more detailed taproot errors 2022-03-15 18:23:42 -07:00
Olaoluwa Osuntokun
79c314d503
txscript: add taproot JSON success/fail reference tests
In this commit, we add a total of 2760 taproot reference tests generated
by the bitcoind functional tests located at:
https://github.com/bitcoin/bitcoin/blob/master/test/functional/feature_taproot.py.
The tests aren't deterministic (fresh private keys are generated), so we
time we go to update the set of tests, we'll end up with fresh hashes
(the file name is the sha1 of the raw json test) and tests.
2022-03-15 18:23:29 -07:00
Olaoluwa Osuntokun
5f8660e5c3
txscript: implement OP_CHECKSIGADD
In this commit, we implement OP_CHECKSIGADD which replaces
OP_CHECKMULTISIG* in the tapscript execution environment.
2022-03-15 18:23:26 -07:00
Olaoluwa Osuntokun
3ce6130ee4
txscript: implement OP_CHECKSIG semantics for tapscript validation
In this commit, we implement the new checksig semantics as part of
tapscript validation. Namely:

  * OP_CHECKSIGVERIFY no longer pops the OP_TRUE off the stack (TODO(roasbeef): verify))

  * the new sig ops semantics are added where each sig deducts 50 from a
    starting budget of 50+the weight of the witness

  * NULLFAIL is always enforced, meaning invalid sigs MUST be an empty sig array
2022-03-15 18:23:23 -07:00
Olaoluwa Osuntokun
a4beed9f72
txscript: add new OpcodePosition method to tokenizer to save code sep position
We'll need this to properly generate the sighash during tapscript
validation later
2022-03-15 18:23:21 -07:00
Olaoluwa Osuntokun
3c6be738ed
txscript: always enforce MINIMAL_IF during tapscript execution 2022-03-15 18:23:18 -07:00
Olaoluwa Osuntokun
a7a8ad7d37
txscript: disable OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY for tapscript 2022-03-15 18:23:16 -07:00
Olaoluwa Osuntokun
c1eb15044e
txscript: implement script path verification
In this commit, we use the recently added control block and script tree
verification+generation routines to implement full script path
verification within the VM. This includes verifying the script reveal
commitment, and recursing one layer deeper to execute the revealed
witness script as specified by BIP 342.
2022-03-15 18:23:13 -07:00
Olaoluwa Osuntokun
17e4609494
txscript: add AssembleTaprootScriptTree func for creating input witnesses
In this commit, we add a new AssembleTaprootScriptTree function that
given a list of tapscript leaves, generates a valid tapscript root,
along with the auxiliary proof data needed to spend each output.
2022-03-15 18:23:11 -07:00
Olaoluwa Osuntokun
6fc4199ee4
txscript: add new RawTxInTapscriptSignature to generate tapsript sigs
In this commit, we add a new function `RawTxInTapscriptSignature` that
will be used to generate signatures in the _tapscript_ context. Note
that this differs from top-level taproot as a distinct sighash is used,
and we _always_ accept a root hash to perform the proper tweak.
2022-03-15 18:23:08 -07:00
Olaoluwa Osuntokun
37f8c8ba0a
txscript: add VerifyTaprootLeafCommitment function
In this commit, we add a new function to verify the taproot merkle
commitment of a given tapscript leaf. Along the way we add some helper
functions which can be used to construct a taproot output given the raw
script root.
2022-03-15 18:23:06 -07:00
Olaoluwa Osuntokun
5c4a29b9d1
txscript: introduce new ControlBlock struct along w/ parsing routine
In this commit, we add a new struct to represent the ControlBlock
structure used to feed in the tapscript leaf inclusion proof into the
witness tack. The `ParseControlBlock` parses a would-be control block
and returns an error if it's incorrectly formatted.
2022-03-15 18:23:03 -07:00
Olaoluwa Osuntokun
11dd820740
txscript: add new ScriptHasOpSuccess utility method
We'll use this to examine if a script has any OP_SUCCESS op codes during
pre-processing before we attempt full tapscript execution.
2022-03-15 18:23:01 -07:00
Olaoluwa Osuntokun
a7c3db40af
txscript: use keyBytes instead of ScriptHash for segwit utilities 2022-03-15 18:22:58 -07:00
Olaoluwa Osuntokun
2ac743dc9f
txscript: add VM verification logic for top-level taproot keyspends
In this commit, we add the initial verification logic for top-level
taproot keyspends. Keyspends use the base BIP 341 sighash digest and
don't require any tapscript level functionality for validation.
2022-03-15 18:22:56 -07:00
Olaoluwa Osuntokun
938c1930da
txscript: add new functions for signing a top-level taproot output
In this commit, we add two new functions: one for signing a raw
top-level taproot keyspend, and another for generating a valid witness
for a keyspend.
2022-03-15 18:22:53 -07:00
Olaoluwa Osuntokun
1ac34b75dc
txscript: use new signature verifiers for existing CHECKSIG ops
In this commit, we use the recently added checksig verifiers to validate
signatures for pre-segwit, and segwit v0 scripts.
2022-03-15 18:22:51 -07:00
Olaoluwa Osuntokun
abeaf4e334
txscript: introduce new signatureVerifier interface to abstract over schnorr/ecdsa
In this commit, we add a new signatureVerifier interface that will allow
us to consolidate a lot of code as we'll now have 4 distinct sig+sighash
types to verify:
  1. pre-segwit
  2. segwit v0
  3. segwit v1 (taproot key spend)
  4. tapscript spends

We'll need to be able to handle 3 of the cases for the modified
OP_CHECKSIG operator. This new abstraction allows us to keep the
implementation of the function somewhat succinct.

In this commit we implement a verifier for #3 which is needed to verify
the top-level taproot keyspend. We expose the verifier using a new
VerifyTaprootKeySpend function.
2022-03-15 18:22:48 -07:00
Olaoluwa Osuntokun
1cd509d9a5
txscript: update SigCache to cache both ECDSA and Schnorr signatures
In this commit, we make the sigCache slightly more general in order to
be able to cache both ECDSA and Schnorr signatures. The cache is now
based off of byte slices (the values) rather than the direct objects. We
rely on the fact that the sighash for ecdsa and the schnorr types are
distinct, so we can keep using the same top-level sighash key.

In the future with Go type params, we can use a type param here instead
as they all have an `IsEqual` method.
2022-03-15 18:22:45 -07:00
Olaoluwa Osuntokun
e781b66e2f
txscript: implement BIP 341+342 segwit v1 taproot+tapscript
In this commit, we implement the new BIP 341+342 taproot sighash digest
computation. The digest is similar, but re-orders some fragments and
also starts to commit to the input values of all the transactions in the
SIGHASH_ALL case. A new implicit sighash flag, SIGHASH_DEFAULT has been
added that allows signatures to always be 64-bytes for the common case.

The hashcache has been updated as well to store both the v0 and v1 mid
state hashes. The v0 hashes are a double-sha of the contents, while the
v1 hash is a single sha. As a result, if a transaction spends both v0
and v1 inputs, then we 're able to re-use all the intermediate hashes.

As the sighash computation needs the input values and scripts, we create
an abstraction: the PrevOutFetcher to give the caller flexibility w.r.t
how this is done. We also create a `CannedPrevOutputFetcher` that holds
the information in a map for a single input.

A series of function options are also added to allow re-use of the same
base sig hash calculation for both BIP 341 and 342.
2022-03-15 18:22:43 -07:00
Olaoluwa Osuntokun
6ecc72e5e6
txscript: move sighash computations to new file 2022-03-15 18:22:40 -07:00
Olaoluwa Osuntokun
30d93272a8
txscript: add new IsPayToTaproot utility func 2022-03-15 18:22:38 -07:00
Olaoluwa Osuntokun
cfe801fe2e
txscript: move hash cache mid-state computation to hashcache.go file 2022-03-15 18:22:32 -07:00
Brian Stafford
3ddf1b51a6
txscript: add taproot support to PayToAddrScript
Add taproot address handling in PayToAddrScript. Adds a test and
also some missing tests for p2wsh and p2wpkh addresses.
2022-03-15 18:22:30 -07:00
Brian Stafford
37964e550b
txscript: add some txscript support for parsing taproot scripts 2022-03-15 18:22:27 -07:00
Brian Stafford
bfd0f4a492
txscript: add taproot script type
Add the WitnessV1TaprootTy script class and return it from
GetScriptClass / typeOfScript.

Bump the btcutil dep to leverage new taproot address type.
2022-03-15 18:22:25 -07:00
Olaoluwa Osuntokun
eb61742c5d
btcec/v2: create new ecdsa package
In this commit, we create a new package to house the ECDSA-specific
logic in the new `btcec/v2` pacakge. Thsi c hange is meant to mirror the
structure of the `dcrec` package, as we'll soon slot in our own custom
BIP-340 implementation.
2022-01-31 14:25:39 -08:00
Olaoluwa Osuntokun
eee3c3b337
multi: switch project over to using btcec/v2 2022-01-26 16:10:17 -08:00
Olaoluwa Osuntokun
caac0f821a
multi: update btcutil imports to point to new sub-module
In this commit, we update all the btcutil imports to point to the new
sub-module.

In the same commit, we also modify the recently added `btcutil/go.mod`
file as we need to continue pointing to the _old_ version of btcd, until
we merge this PR and push a new tag.
2022-01-10 18:44:58 -08:00
Dave Collins
b95ba0ac95
txscript: Make op callbacks take opcode and data.
This converts the callback function defined on the internal opcode
struct to accept the opcode and data slice instead of a parsed opcode as
the final step towards removing the parsed opcode struct and associated
supporting code altogether.

It also updates all of the callbacks and tests accordingly and finally
removes the now unused parsedOpcode struct.

The final results for the raw script analysis and tokenizer
optimizations are as follows:

benchmark                                       old ns/op     new ns/op     delta
BenchmarkIsPayToScriptHash-8                    62393         0.51          -100.00%
BenchmarkIsPubKeyHashScript-8                   62228         0.56          -100.00%
BenchmarkGetSigOpCount-8                        61051         658           -98.92%
BenchmarkExtractPkScriptAddrsLarge-8            60713         17.2          -99.97%
BenchmarkExtractPkScriptAddrs-8                 289           17.9          -93.81%
BenchmarkIsWitnessPubKeyHash-8                  61688         0.42          -100.00%
BenchmarkIsUnspendable-8                        656           520           -20.73%
BenchmarkExtractAtomicSwapDataPushesLarge-8     61332         44.0          -99.93%
BenchmarkExtractAtomicSwapDataPushes-8          990           260           -73.74%
BenchmarkDisasmString-8                         102902        39754         -61.37%
BenchmarkGetPreciseSigOpCount-8                 130223        715           -99.45%
BenchmarkScriptParsing-8                        63464         681           -98.93%
BenchmarkIsMultisigScriptLarge-8                64166         5.83          -99.99%
BenchmarkIsMultisigScript-8                     630           58.5          -90.71%
BenchmarkPushedData-8                           64837         1779          -97.26%
BenchmarkCalcSigHash-8                          3627895       3605459       -0.62%
BenchmarkIsPubKeyScript-8                       62323         2.83          -100.00%
BenchmarkIsPushOnlyScript-8                     62412         569           -99.09%
BenchmarkIsWitnessScriptHash-8                  61243         0.56          -100.00%
BenchmarkGetScriptClass-8                       61515         16.4          -99.97%
BenchmarkIsNullDataScript-8                     62495         2.53          -100.00%
BenchmarkIsMultisigSigScriptLarge-8             69328         2.52          -100.00%
BenchmarkIsMultisigSigScript-8                  2375          141           -94.06%
BenchmarkGetWitnessSigOpCountP2WKH-8            504           72.0          -85.71%
BenchmarkGetWitnessSigOpCountNested-8           1158          136           -88.26%
BenchmarkIsWitnessPubKeyHash-8                  68927         0.53          -100.00%
BenchmarkIsWitnessScriptHash-8                  62774         0.63          -100.00%

benchmark                                       old allocs     new allocs     delta
BenchmarkIsPayToScriptHash-8                    1              0              -100.00%
BenchmarkIsPubKeyHashScript-8                   1              0              -100.00%
BenchmarkGetSigOpCount-8                        1              0              -100.00%
BenchmarkExtractPkScriptAddrsLarge-8            1              0              -100.00%
BenchmarkExtractPkScriptAddrs-8                 1              0              -100.00%
BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
BenchmarkIsUnspendable-8                        1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushesLarge-8     1              0              -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          2              1              -50.00%
BenchmarkDisasmString-8                         46             51             +10.87%
BenchmarkGetPreciseSigOpCount-8                 3              0              -100.00%
BenchmarkScriptParsing-8                        1              0              -100.00%
BenchmarkIsMultisigScriptLarge-8                1              0              -100.00%
BenchmarkIsMultisigScript-8                     1              0              -100.00%
BenchmarkPushedData-8                           7              6              -14.29%
BenchmarkCalcSigHash-8                          1335           712            -46.67%
BenchmarkIsPubKeyScript-8                       1              0              -100.00%
BenchmarkIsPushOnlyScript-8                     1              0              -100.00%
BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%
BenchmarkGetScriptClass-8                       1              0              -100.00%
BenchmarkIsNullDataScript-8                     1              0              -100.00%
BenchmarkIsMultisigSigScriptLarge-8             5              0              -100.00%
BenchmarkIsMultisigSigScript-8                  3              0              -100.00%
BenchmarkGetWitnessSigOpCountP2WKH-8            2              0              -100.00%
BenchmarkGetWitnessSigOpCountNested-8           4              0              -100.00%
BenchmarkIsWitnessPubKeyHash-8                  1              0              -100.00%
BenchmarkIsWitnessScriptHash-8                  1              0              -100.00%

benchmark                                       old bytes     new bytes     delta
BenchmarkIsPayToScriptHash-8                    311299        0             -100.00%
BenchmarkIsPubKeyHashScript-8                   311299        0             -100.00%
BenchmarkGetSigOpCount-8                        311299        0             -100.00%
BenchmarkExtractPkScriptAddrsLarge-8            311299        0             -100.00%
BenchmarkExtractPkScriptAddrs-8                 768           0             -100.00%
BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
BenchmarkIsUnspendable-8                        1             0             -100.00%
BenchmarkExtractAtomicSwapDataPushesLarge-8     311299        0             -100.00%
BenchmarkExtractAtomicSwapDataPushes-8          3168          96            -96.97%
BenchmarkDisasmString-8                         389324        130552        -66.47%
BenchmarkGetPreciseSigOpCount-8                 623367        0             -100.00%
BenchmarkScriptParsing-8                        311299        0             -100.00%
BenchmarkIsMultisigScriptLarge-8                311299        0             -100.00%
BenchmarkIsMultisigScript-8                     2304          0             -100.00%
BenchmarkPushedData-8                           312816        1520          -99.51%
BenchmarkCalcSigHash-8                          1373812       1290507       -6.06%
BenchmarkIsPubKeyScript-8                       311299        0             -100.00%
BenchmarkIsPushOnlyScript-8                     311299        0             -100.00%
BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
BenchmarkGetScriptClass-8                       311299        0             -100.00%
BenchmarkIsNullDataScript-8                     311299        0             -100.00%
BenchmarkIsMultisigSigScriptLarge-8             330035        0             -100.00%
BenchmarkIsMultisigSigScript-8                  9472          0             -100.00%
BenchmarkGetWitnessSigOpCountP2WKH-8            1408          0             -100.00%
BenchmarkGetWitnessSigOpCountNested-8           3200          0             -100.00%
BenchmarkIsWitnessPubKeyHash-8                  311299        0             -100.00%
BenchmarkIsWitnessScriptHash-8                  311299        0             -100.00%
2021-11-16 18:49:46 -08:00
Dave Collins
ef3d06e62b
txscript: Make executeOpcode take opcode and data.
This converts the executeOpcode function defined on the engine to accept
an opcode and data slice instead of a parsed opcode as a step towards
removing the parsed opcode struct and associated supporting code altogether.

It also updates all callers accordingly.
2021-11-16 18:49:41 -08:00
Dave Collins
595d379fa6
txscript: Remove unused parseScriptTemplate func.
Also remove tests associated with the func accordingly.
2021-11-16 18:49:38 -08:00
Dave Collins
ca044fefcb
txscript: Remove unused parsedOpcode.bytes func. 2021-11-16 18:49:36 -08:00
Dave Collins
491b7b59fc
txscript: Remove unused unparseScript func.
Also remove tests associated with unparsing opcodes accordingly.
2021-11-16 18:49:33 -08:00
Conner Fromknecht
e06b11a999
txscript: Remove unused calcWitnessSignatureHash 2021-11-16 18:49:31 -08:00
Dave Collins
6e5fbf8ea8
txscript: Remove unused parseScript func. 2021-11-16 18:49:28 -08:00
Conner Fromknecht
7533672993
txscript/pkscript: Use finalOpcodeData to extract redeem script 2021-11-16 18:49:25 -08:00
Conner Fromknecht
69f3a39c1c
txscript/sign: Use calcWitnessSigHashRaw for witness sigs 2021-11-16 18:49:23 -08:00
Conner Fromknecht
94e99cf6b7
txscript: Rename calcSignatureHashRaw 2021-11-16 18:49:20 -08:00
Dave Collins
911db90858
txscript: Rename removeOpcodeByDataRaw func.
This renames the removeOpcodeByDataRaw to removeOpcodeByData now that
the old version has been removed.
2021-11-16 18:49:18 -08:00
Dave Collins
07ab66b790
txscript: Remove unused removeOpcodeByData func. 2021-11-16 18:49:15 -08:00
Conner Fromknecht
03d1fb0f86
txscript: Remove unused isWitnessProgram 2021-11-16 18:49:13 -08:00
Conner Fromknecht
06c8bea6c7
txscript: Remove unused calcSignatureHash 2021-11-16 18:49:10 -08:00
Dave Collins
d6b968c3ea
txscript: Refactor engine to use raw scripts.
This refactors the script engine to store and step through raw scripts
by making using of the new zero-allocation script tokenizer as opposed
to the less efficient method of storing and stepping through parsed
opcodes.  It also improves several aspects while refactoring such as
optimizing the disassembly trace, showing all scripts in the trace in
the case of execution failure, and providing additional comments
describing the purpose of each field in the engine.

It should be noted that this is a step towards removing the parsed
opcode struct and associated supporting code altogether, however, in
order to ease the review process, this retains the struct and all
function signatures for opcode execution which make use of an individual
parsed opcode.  Those will be updated in future commits.

The following is an overview of the changes:

- Modify internal engine scripts slice to use raw scripts instead of
  parsed opcodes
- Introduce a tokenizer to the engine to track the current script
- Remove no longer needed script offset parameter from the engine since
  that is tracked by the tokenizer
- Add an opcode index counter for disassembly purposes to the engine
- Update check for valid program counter to only consider the script
  index
  - Update tests for bad program counter accordingly
- Rework the NewEngine function
  - Store the raw scripts
  - Setup the initial tokenizer
  - Explicitly check against version 0 instead of DefaultScriptVersion
    which would break consensus if changed
  - Check the scripts parse according to version 0 semantics to retain
    current consensus rules
  - Improve comments throughout
- Rework the Step function
  - Use the tokenizer and raw scripts
  - Create a parsed opcode on the fly for now to retain existing
    opcode execution function signatures
  - Improve comments throughout
- Update the Execute function
  - Explicitly check against version 0 instead of DefaultScriptVersion
    which would break consensus if changed
  - Improve the disassembly tracing in the case of error
- Update the CheckErrorCondition function
  - Modify clean stack error message to make sense in all cases
  - Improve the comments
- Update the DisasmPC and DisasmScript functions on the engine
  - Use the tokenizer
  - Optimize construction via the use of strings.Builder
- Modify the subScript function to return the raw script bytes since the
  parsed opcodes are no longer stored
- Update the various signature checking opcodes to use the raw opcode
  data removal and signature hash calculation functions since the
  subscript is now a raw script
  - opcodeCheckSig
  - opcodeCheckMultiSig
  - opcodeCheckSigAlt
2021-11-16 18:49:08 -08:00
Dave Collins
54036e8bab
txscript: Convert to use non-parsed opcode disasm.
This converts the engine's current program counter disasembly to make
use of the standalone disassembly function to remove the dependency on
the parsed opcode struct.

It also updates the tests accordingly.
2021-11-16 18:49:05 -08:00
Dave Collins
710bd5646e
txscript: Make min push accept raw opcode and data.
This converts the checkMinimalDataPush function defined on a parsed
opcode to a standalone function which accepts an opcode and data slice
instead in order to make it more flexible for raw script analysis.

It also updates all callers accordingly.
2021-11-16 18:49:03 -08:00
Dave Collins
62c608f265
txscript: Make isConditional accept raw opcode.
This converts the isConditional function defined on a parsed opcode to a
standalone function named isOpcodeConditional which accepts an opcode as
a byte instead in order to make it more flexible for raw script
analysis.

It also updates all callers accordingly.
2021-11-16 18:49:00 -08:00
Dave Collins
c6410257eb
txscript: Make alwaysIllegal accept raw opcode.
This converts the alwaysIllegal function defined on a parsed opcode to a
standalone function named isOpcodeAlwaysIllegal which accepts an opcode
as a byte instead in order to make it more flexible for raw script
analysis.

It also updates all callers accordingly.
2021-11-16 18:48:58 -08:00
Dave Collins
484f7b1fef
txscript: Make isDisabled accept raw opcode.
This converts the isDisabled function defined on a parsed opcode to a
standalone function which accepts an opcode as a byte instead in order
to make it more flexible for raw script analysis.

It also updates all callers accordingly.
2021-11-16 18:48:55 -08:00
Conner Fromknecht
a2ab5b6681
txscript: Use removeOpcodeRaw for CODESEP in calcSigHash 2021-11-16 18:48:52 -08:00