-
Notifications
You must be signed in to change notification settings - Fork 400
Update spec for tapscript opcodes #1019
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
da91eb4 to
68ef3d3
Compare
doc/tapscript_opcodes.md
Outdated
| 9. If `n=8`, Push the annex onto the stack where the annex includes the prefix(0x50). If the annex does not exist, push an empty vector | ||
| 10. Otherwise treat as `OP_SUCCESS` and return true (without executing rest of script). | ||
| - Define `OP_SUCCESS200` as `OP_INSPECTCURRENTINPUT` that pushes the current input index(4) as little-endian onto the stack | ||
| 2. If `n=0`, Push the outpoint_flag(1) as defined in [Modified BIP-341 SigMsg for Elements](https://gist.github.com/roconnor-blockstream/9f0753711153de2e254f7e54314f7169) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This paragraph isn't formatted correctly. Maybe because you need a 1. here. Tip: I think if you use 1. 1. 1. everywhere it will autonumber it for you.
doc/tapscript_opcodes.md
Outdated
| - Define `OP_SUCCESS206` as `OP_SUB64`: pop the first number(8 byte LE) as `b` followed another pop for `a`(8 byte LE). Push a - b onto the stack. Push 1 `CScriptNum` if there is no overflow. Overflow behavior defined above. | ||
| - Define `OP_SUCCESS207` as `OP_MUL64`: pop the first number(8 byte LE) as `b` followed another pop for `a`(8 byte LE). Push `a*b` onto the stack. Push 1 `CScriptNum` if there is no overflow. Overflow behavior defined above. | ||
| - Define `OP_SUCCESS208` as `OP_DIV64`: pop the first number(8 byte LE) as `b` followed another pop for `a`(8 byte LE). First push remainder `a%b`(must be non-negative and less than |b|) onto the stack followed by quotient(`a//b`) onto the stack. Abort if `b=0`. Push 1 `CScriptNum` if there is no overflow. Overflow behavior defined above. | ||
| - Define `OP_SUCCESS208` as `OP_DIV64`(Does not fail): pop the first number(8 byte LE) as `b` followed another pop for `a`(8 byte LE). First push remainder `a%b`(must be non-negative and less than |b|) onto the stack followed by quotient(`a//b`) onto the stack. If `b==0`, treat as overflow as defined above. Push 1 `CScriptNum` if there is no overflow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Does not fail)
It can fail right? When b is 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it does fail. This is an error on my part.
71022b3 to
56c8a8e
Compare
doc/tapscript_opcodes.md
Outdated
| 1. Define `OP_SUCCESS207` as `OP_INSPECTOUTPUTASSET`: Pop a `CScriptNum` input index `idx` and push the `nAsset` as a tuple, first push the assetID(32), followed by the prefix(1) | ||
| 1. Define `OP_SUCCESS208` as `OP_INSPECTOUTPUTVALUE`: Pop a `CScriptNum` input index `idx` and push the `nValue` as a tuple, value(8, 32) followed by prefix | ||
| 1. Define `OP_SUCCESS209` as `OP_INSPECTOUTPUTNONCE`: Pop a `CScriptNum` input index `idx` and push the `nNonce`(33) onto the stack. If the nonce is null, push an empty vector onto the stack. | ||
| 1. Define `OP_SUCCESS210` as `OP_INSPECTOUTPUTSCRIPTPUBKEY`: Pop a `CScriptNum` input index `idx` and push the scriptPubkey(34) onto the stack. Note that the compact size prefix is not pushed onto the stack. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This description is incorrect. ScriptPubKeys can be arbitrarily large.
doc/tapscript_opcodes.md
Outdated
| 1. Define `OP_SUCCESS212` as `OP_INSPECTLOCKTIME`: Pop a `CScriptNum` input index `idx` and push the nLockTime(4) as little-endian. | ||
| 1. Define `OP_SUCCESS213` as `OP_INSPECTNUMINPUTS`: Pop a `CScriptNum` input index `idx` and push the number of inputs(4) as little-endian | ||
| 1. Define `OP_SUCCESS214` as `OP_INSPECTNUMOUTPUTS`: Pop a `CScriptNum` input index `idx` and push the number of outputs(4) as little-endian | ||
| 1. Define `OP_SUCCESS215` as `OP_TXSIZE`: Pop a `CScriptNum` input index `idx` and push the transaction size in vbytes (4) as little-endian |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OP_TXWEIGHT is probably better.
doc/tapscript_opcodes.md
Outdated
| 1. Define `OP_SUCCESS209` as `OP_INSPECTOUTPUTNONCE`: Pop a `CScriptNum` input index `idx` and push the `nNonce`(33) onto the stack. If the nonce is null, push an empty vector onto the stack. | ||
| 1. Define `OP_SUCCESS210` as `OP_INSPECTOUTPUTSCRIPTPUBKEY`: Pop a `CScriptNum` input index `idx` and push the scriptPubkey(34) onto the stack. Note that the compact size prefix is not pushed onto the stack. | ||
| - Transaction introspection opcodes: | ||
| 1. Define `OP_SUCCESS211` as `OP_INSPECTVERSION`: Pop a `CScriptNum` input index `idx` and push the nVersion(4) as little-endian. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These don't have an index. Nothing is popped.
b9b72cb to
c748f4e
Compare
doc/tapscript_opcodes.md
Outdated
| 1. Define `OP_SUCCESS204` as `OP_INSPECTINPUTSEQUENCE`: Pop a `CScriptNum` input index `idx` and push the `nSequence`(4) as little-endian number. | ||
| 1. Define `OP_SUCCESS205` as `OP_INSPECTINPUTISSUANCE`: Pop a `CScriptNum` input index `idx` and push the assetIssuance information if the asset has issuance, otherwise push an empty vector. Asset Issuance information is pushed as follows | ||
| - Push `nInflationKeys` as tuple, value(8, 32) followed by push for prefix(1). In case `nInflationKeys` is null, push an empty vector on stack top. | ||
| - Push `nAmount` as a tuple, value(8, 32) followed by a push for prefix(1). This cannot be null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that nAmount can be null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, In both cases it might make sense to replace null values with an explicit 0 amount. I think that might be more useful for programming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think users are probably interested in the distinction between NullValue and zero explicit amount.
doc/tapscript_opcodes.md
Outdated
| - Transaction input introspection opcodes: | ||
| 1. Define `OP_SUCCESS199` as `OP_INSPECTINPUTOUTPOINT`: Pop a `CScriptNum` input index `idx` and push the outpoint as a tuple. First push the `txid`(32) of the `prev_out`, followed by a 4 byte push of `vout` followed by a pushed for push the outpoint_flag(1) as defined in [Modified BIP-341 SigMsg for Elements](https://gist.github.com/roconnor-blockstream/9f0753711153de2e254f7e54314f7169). | ||
| 1. Define `OP_SUCCESS200` as `OP_INSPECTINPUTASSET`: Pop a `CScriptNum` input index `idx` and push the `nAsset` onto the stack as two elements. The first push the assetID(32), followed by the prefix(1) | ||
| 1. Define `OP_SUCCESS201` as `OP_INSPECTINPUTVALUE`: Pop a `CScriptNum` input index `idx` and push the `nValue` as a tuple, value(8, 32) followed by prefix(1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a note here and below that explicit values are pushed as little endian values.
doc/tapscript_opcodes.md
Outdated
| - Define `OP_SUCCESS204` as `OP_TAPTWEAK` with the following semantics. Pop the first element as point `P`, second element as script blob `S`. Push the Taptweak on the top of stack `Q = P + H(P||S)*G`. If `|S| > MAX_ELEMENT_SIZE`, the user should use the streaming opcodes to compute the Hash function. | ||
| For opcodes that inspect data that is not committed in sighash, introspection is safe because any changes to the witness data would cause wtxid to change and it would revalidate the tx again. For pegin inputs, the asset/value/script information will be one from the parent chain. | ||
| - Transaction input introspection opcodes: | ||
| 1. Define `OP_SUCCESS199` as `OP_INSPECTINPUTOUTPOINT`: Pop a `CScriptNum` input index `idx` and push the outpoint as a tuple. First push the `txid`(32) of the `prev_out`, followed by a 4 byte push of `vout` followed by a pushed for push the outpoint_flag(1) as defined in [Modified BIP-341 SigMsg for Elements](https://gist.github.com/roconnor-blockstream/9f0753711153de2e254f7e54314f7169). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here: the 4 byte push of the vout is little endian.
Typo: followed by a pushed for push
| 1. Define `OP_SUCCESS206` as `OP_INSPECTOUTPUTASSET`: Pop a `CScriptNum` input index `idx` and push the `nAsset` as a tuple, first push the assetID(32), followed by the prefix(1) | ||
| 1. Define `OP_SUCCESS207` as `OP_INSPECTOUTPUTVALUE`: Pop a `CScriptNum` input index `idx` and push the `nValue` as a tuple, value(8, 32) followed by prefix | ||
| 1. Define `OP_SUCCESS208` as `OP_INSPECTOUTPUTNONCE`: Pop a `CScriptNum` input index `idx` and push the `nNonce`(33) onto the stack. If the nonce is null, push an empty vector onto the stack. | ||
| 1. Define `OP_SUCCESS209` as `OP_INSPECTOUTPUTSCRIPTPUBKEY`: Pop a `CScriptNum` input index `idx` and push the scriptPubkey onto the stack. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pegouts and their PAK proofs won't fit in 520 bytes. So we will need to push the hash of the scriptpubkey in the non-segwit case. Then they can, in principle be verified with the rolling SHA256 opcodes.
However the implementation will require a cache to avoid DOS.
doc/tapscript_opcodes.md
Outdated
| 1. Define `OP_SUCCESS228` as `OP_TAPTWEAKVERIFY` with the following semantics: Pop the three elements as: 1) 32 byte X-only internal key `P`, 2) 32 byte scalar `k` and 3) 33 byte compressed point `Q`. Abort if `P`, `Q` is invalid or `k` is not 32 bytes and outside of secp256k1 curve order. Abort if `Q != P + k*G` where `G` is the generator for secp256k1. | ||
|
|
||
| 6. **Changes to existing Opcodes**: | ||
| - Add `OP_CHECKSIGFROMSTACK` and `OP_CHECKSIGFROMSTACKVERIFY` to follow the semantics from bip340 when witness program is v1. In more detail, the opcodes pops three elements stack 1) 32 byte `pk` Xonly public key 2) Variable length message `msg` and 3) 64 byte Schnorr signature `sig`. Let `res = BIP340_verify(pk, msg, sig)` where `BIP340_verify` is defined for elements [here](https://github.com/ElementsProject/elements/blob/master/doc/taproot-sighash.mediawiki). Note that this is different form bitcoin BIP340 as it uses different tagged hashes. If opcode is `OP_CHECKSIGFROMSTACKVERIFY`, abort if the verification fails. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this is different form bitcoin BIP340 as it uses different tagged hashes.
This is incorrect.
doc/tapscript_opcodes.md
Outdated
| - Transaction introspection opcodes: | ||
| 1. Define `OP_SUCCESS210` as `OP_INSPECTVERSION`: Push the nVersion(4) as little-endian. | ||
| 1. Define `OP_SUCCESS211` as `OP_INSPECTLOCKTIME`: Push the nLockTime(4) as little-endian. | ||
| 1. Define `OP_SUCCESS212` as `OP_INSPECTNUMINPUTS`: Push the number of inputs(4) as little-endian |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NUMINPUTS and NUMOUPUTS should probably push a CScriptNum value.
doc/tapscript_opcodes.md
Outdated
| 1. Define `OP_SUCCESS211` as `OP_INSPECTLOCKTIME`: Push the nLockTime(4) as little-endian. | ||
| 1. Define `OP_SUCCESS212` as `OP_INSPECTNUMINPUTS`: Push the number of inputs(4) as little-endian | ||
| 1. Define `OP_SUCCESS213` as `OP_INSPECTNUMOUTPUTS`: Push the number of outputs(4) as little-endian | ||
| 1. Define `OP_SUCCESS214` as `OP_TXWEIGHT`: Push the transaction weight (4) as little-endian |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider making TXWEIGHT a 64 bit value. I think it will commonly be used in fee-rate calculations. The other case is some sort of absolute bound, but that mostly works as a 64 bit value too.
I could go either way on this though.
doc/tapscript_opcodes.md
Outdated
| 6. **Changes to existing Opcodes**: | ||
| - Add `OP_CHECKSIGFROMSTACK` and `OP_CHECKSIGFROMSTACKVERIFY` to follow the semantics from bip340-342 when witness program is v1. | ||
| 5. **Crypto**: In order to allow more complex operations on elements, we introduce the following new crypto-operators. Each opcode counts as 50 towards the sigops budget. | ||
| 1. Define `OP_SUCCESS227` as `OP_ECMULSCALAREXPVERIFY`which pops three elements from stack as described below: 1) a 32 byte scalar `k`. 2) Compressed EC point `P`, and 3) compressed EC point `Q`. Abort if `P`, `Q` is invalid or `k` is not 32 bytes and outside of secp256k1 curve order. Abort if `Q != k*P`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The endianness of the scalars needs to be documented.
doc/tapscript_opcodes.md
Outdated
| 6. **Changes to existing Opcodes**: | ||
| - Add `OP_CHECKSIGFROMSTACK` and `OP_CHECKSIGFROMSTACKVERIFY` to follow the semantics from bip340-342 when witness program is v1. | ||
| 5. **Crypto**: In order to allow more complex operations on elements, we introduce the following new crypto-operators. Each opcode counts as 50 towards the sigops budget. | ||
| 1. Define `OP_SUCCESS227` as `OP_ECMULSCALAREXPVERIFY`which pops three elements from stack as described below: 1) a 32 byte scalar `k`. 2) Compressed EC point `P`, and 3) compressed EC point `Q`. Abort if `P`, `Q` is invalid or `k` is not 32 bytes and outside of secp256k1 curve order. Abort if `Q != k*P`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OP_ECMULSCALAREXPVERIFY should be called OP_ECMULSCALARVERIFY?
443a2b3 to
a651f7e
Compare
doc/tapscript_opcodes.md
Outdated
| - Define `OP_SUCCESS198` as `OP_SHA256FINALIZE` to pop a SHA256 context and bytestring and push a SHA256 hash value after adding the bytestring and completing the padding. | ||
| 1. **Streaming Opcodes for streaming hashes**: There is an existing limitation of `MAX_SCRIPT_ELEMENT_SIZE`(520 bytes) because of which we cannot operate hash functions like `OP_SHA256` on messages more than 520 bytes. This allows hashing on more than 520 bytes while still preserving the existing security against resource exhaustion attacks. The proposal for this by Russell O'Connor can be found in the description [here](https://github.com/ElementsProject/elements/pull/817). | ||
| 1. Define `OP_SUCCESS196` as `OP_SHA256INITIALIZE` which pops a bytestring and push SHA256 context creating by adding the bytestring to the initial SHA256 context. | ||
| 1. Define `OP_SUCCESS197` as `OP_SHA256UPDATE` which frist pops a SHA256 contextm then pops another bytestring and pushes an updated context by adding the bytestring to the data stream being hashed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/frist/first
s/contextm/context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also updated to first pop the bytestring and then the context object
doc/tapscript_opcodes.md
Outdated
| 6. **Changes to existing Opcodes**: | ||
| - Add `OP_CHECKSIGFROMSTACK` and `OP_CHECKSIGFROMSTACKVERIFY` to follow the semantics from bip340-342 when witness program is v1. | ||
| 5. **Crypto**: In order to allow more complex operations on elements, we introduce the following new crypto-operators. Each opcode counts as 50 towards the sigops budget. | ||
| 1. Define `OP_SUCCESS227` as `OP_ECMULSCALARVERIFY`which pops three elements from stack as described below: 1) a 32 byte big endian scalar `k`. 2) Compressed EC point `P`, and 3) compressed EC point `Q`. Abort if `P`, `Q` is invalid or `k` is not 32 bytes and outside of secp256k1 curve order. Abort if `Q != k*P`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
big endian, unsigned scalar.
1577ed4 fuzz: add fuzz test for segwitv0 and tapscript script interpreters (Andrew Poelstra) 8a20fbe Add XOnlyPubKey::CreateTapTweak (Andrew Poelstra) 68961ca Make consensus checking of tweaks in pubkey.* Taproot-specific (Andrew Poelstra) c3945cb Make XOnlyPubKey act like byte container (Pieter Wuille) 2c5c7eb Update tapscript leaf version (sanket1729) 937343c Add tests for crypto opcodes (sanket1729) 7193636 Add crypto opcodes (sanket1729) 3e7b8c6 Test arithmetic opcodes (sanket1729) 4b90322 Implement arithmetic opcodes (sanket1729) 6092d94 Add tests for introspection (sanket1729) 9346a84 Implement transaction introspection opcodes (sanket1729) 97b53e0 Cache Input/Output ScriptPubkeys sha256 (sanket1729) 61b5152 Expose transaction data via BaseSignatureChecker (sanket1729) 007912e Implement tests for sha256 streaming opcodes (sanket1729) 2df8e99 Implement Streaming SHA256 opcodes (sanket1729) Pull request description: Please refer to the new spec here. #1019 ACKs for top commit: apoelstra: ACK 1577ed4 Tree-SHA512: 297cfe8699982d9575a566eda2f5f4a253968552dbc9ff000440da4d6f5b175a1619d7a5074e1ddf6818e2c51f54a33142a89a63494f26ad946ca09e0cff94c5
|
Merging now that the implementation is merged. |
|
ACK 31c232a |
|
I could have squashed the 14 commits in 1 :P |
|
Lol, yeah, oops, I actually looked at the net diff for this one instead of the individual commits :P |
This is an updating document for the latest specification of tapscript opcodes. This will be updated in parallel while the implementation is in progress