Show Posts
|
Pages: [1] 2 »
|
Great this IDE, I was looking for such a program 5 years ago, but could not find it. I played around with the IDE and it works beautifully. Especially, the 'show all frames' is super helpful. My question: I want to us HTLC like contracts, and want to use Opcodes "OP_CHECKLOCKTIMEVERIFY" and "OP_CHECKSEQUENCEVERIFY", but I couldn't get these to work. I get the following error: [Error: Error: RuntimeError: Error: missing op code OP_CHECKSEQUENCEVERIFY in trace builder] Furthermore, It would be great to have some more examples such as to create 2 out of 3 lock script etc etc. Thanks again for this great tool! Hey there! We just released support for OP_CHECKSIG and added a wallet/key manager to generate script signatures in v0.8.6, and v0.9.0 should be out later this week with support for OP_CHECKMULTISIG/OP_CHECKMULTISIGVERIFY/OP_CHECKSIGADD/OP_CHECKLOCKTIMEVERIFY/OP_CHECKSEQUENCEVERIFY. For those interested in test driving OP_CHECKSIG, you can check out this step-by-step video tutorial and update BitIDE as shown below: Update BitIDE Bitcoin Core Edition: docker pull qedprotocol/bitide:latest docker run -p 1337:1337 -it --rm qedprotocol/bitide:latest
Update BitIDE Liquid Edition: docker pull qedprotocol/bitide-liquid:latest docker run -p 1337:1337 -it --rm qedprotocol/bitide-liquid:latest
Appreciate the feedback and apologize for the incomplete VM implementation, we are closing in on 100% coverage, but still have a few more ops to implement.
|
|
|
I noticed that recently there have been some questions about properly constructing signatures for OP_CHECKSIG in P2TR, so decided to make a video for the curious. This technique can be useful for creating puzzle/other challenges (pay to ZKP =D) that cannot be frontran by folks monitoring the mempool (one unique challenge per public key/tapscript path). Scripts from the videoSetupdocker pull qedprotocol/bitide:latest docker run -p 1337:1337 -it --rm qedprotocol/bitide:latest
user_1_lock.basm/* note that the dummy signature "?2742ce32de496f3d51ddd8b57cee513e982ef66adb51324343a9ec2516281093" can be used to test OP_CHECKSIG in the editor, but must be removed in the tapscript runner witness input before unlocking the UTXO */
<"?2742ce32de496f3d51ddd8b57cee513e982ef66adb51324343a9ec2516281093"> <"some other secret value">
END_EXAMPLE_WITNESS
OP_HASH160 <0xda70d9c91368cc32d8bdaf0dd82f53c07272fd17> OP_EQUALVERIFY
<0x2742ce32de496f3d51ddd8b57cee513e982ef66adb51324343a9ec2516281093> // public key 1 OP_CHECKSIG
user_2_lock.basm// to make a dummy signature for any public key just push a string to the stack containing a question mark followed by the hex encoded public key (x only/last 32 bytes) <"?bee908511ef6d1c5d99ca33ea0db1fbbf313a5c3c08471702595eae888ff012b"> <"super secret value"> END_EXAMPLE_WITNESS OP_HASH160
<0x32cac4959b6bc4aad4bc65fc7b4eab19506359b2> OP_EQUALVERIFY
<0xbee908511ef6d1c5d99ca33ea0db1fbbf313a5c3c08471702595eae888ff012b> // public key 2 OP_CHECKSIG
Would love any feedback on other tutorials anyone may want to see or how things could be made easier to bring in newer bitcoin devs (maybe a button to generate/download a standalone js project that automates the tx with bitcoinjs?).
|
|
|
Just released BitIDE 0.7.0 which includes bug fixes and support for Liquid BTC + a new docker image which includes a local Elements 23.2.1 regtest testnet. To upgrade to the latest version of BitIDE, run: docker pull qedprotocol/bitide:latest docker run -p 1337:1337 -it --rm qedprotocol/bitide:latest
To start a Liquid/Elements regtest + install the Liquid compatible version of BitIDE, run: docker pull qedprotocol/bitide-liquid:latest docker run -p 1337:1337 -it --rm qedprotocol/bitide-liquid:latest
You can also change the vm mode in the web version of BitIDE by selecting "Liquid" in the new IDE Settings tab: Currently supported Elements/Liquid only op codes: - OP_ADD64
- OP_SUB64
- OP_DIV64
- OP_MUL64
- OP_LESSTHAN64
- OP_GREATERTHAN64
- OP_LESSTHANOREQUAL64
- OP_GREATERTHANOREQUAL64
- OP_NEG64
- OP_SCRIPTNUMTOLE64
- OP_LE64TOSCRIPTNUM
- OP_LE32TOLE64
- OP_OR
- OP_XOR
- OP_AND
- OP_CAT
More will be added soon!
|
|
|
As expected, the total bytes for this opcode is quite long, but it seems to be doable.
The interesting part is that you seemed to have also implemented an OP_XOR, OP_OR, OP_AND, OP_MUL, OP_SHIFT and a bunch of other opcodes in the process of making this work.
So do you think there is a case where you can also show that these other disabled opcodes could be enabled back?
Yep, here are polyfills for OP_XOR/OP_AND/OP_OR for 31 bit unsigned script numbers: OP_XOR: OP_0 OP_TOALTSTACK OP_DUP <1073741824> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1073741824> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1073741824> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1073741824> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <1073741824> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <536870912> OP_LESSTHAN OP_IF OP_0 OP_ELSE <536870912> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <536870912> OP_LESSTHAN OP_IF OP_0 OP_ELSE <536870912> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <536870912> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <268435456> OP_LESSTHAN OP_IF OP_0 OP_ELSE <268435456> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <268435456> OP_LESSTHAN OP_IF OP_0 OP_ELSE <268435456> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <268435456> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <134217728> OP_LESSTHAN OP_IF OP_0 OP_ELSE <134217728> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <134217728> OP_LESSTHAN OP_IF OP_0 OP_ELSE <134217728> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <134217728> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <67108864> OP_LESSTHAN OP_IF OP_0 OP_ELSE <67108864> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <67108864> OP_LESSTHAN OP_IF OP_0 OP_ELSE <67108864> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <67108864> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <33554432> OP_LESSTHAN OP_IF OP_0 OP_ELSE <33554432> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <33554432> OP_LESSTHAN OP_IF OP_0 OP_ELSE <33554432> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <33554432> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <16777216> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16777216> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <16777216> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16777216> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <16777216> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <8388608> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8388608> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <8388608> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8388608> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <8388608> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <4194304> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4194304> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <4194304> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4194304> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <4194304> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <2097152> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2097152> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <2097152> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2097152> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <2097152> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <1048576> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1048576> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1048576> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1048576> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <1048576> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <524288> OP_LESSTHAN OP_IF OP_0 OP_ELSE <524288> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <524288> OP_LESSTHAN OP_IF OP_0 OP_ELSE <524288> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <524288> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <262144> OP_LESSTHAN OP_IF OP_0 OP_ELSE <262144> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <262144> OP_LESSTHAN OP_IF OP_0 OP_ELSE <262144> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <262144> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <131072> OP_LESSTHAN OP_IF OP_0 OP_ELSE <131072> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <131072> OP_LESSTHAN OP_IF OP_0 OP_ELSE <131072> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <131072> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <65536> OP_LESSTHAN OP_IF OP_0 OP_ELSE <65536> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <65536> OP_LESSTHAN OP_IF OP_0 OP_ELSE <65536> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <65536> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <32768> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32768> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <32768> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32768> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <32768> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <16384> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16384> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <16384> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16384> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <16384> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <8192> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8192> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <8192> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8192> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <8192> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <4096> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4096> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <4096> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4096> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <4096> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <2048> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2048> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <2048> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2048> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <2048> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <1024> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1024> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1024> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1024> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <1024> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <512> OP_LESSTHAN OP_IF OP_0 OP_ELSE <512> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <512> OP_LESSTHAN OP_IF OP_0 OP_ELSE <512> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <512> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <256> OP_LESSTHAN OP_IF OP_0 OP_ELSE <256> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <256> OP_LESSTHAN OP_IF OP_0 OP_ELSE <256> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <256> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <128> OP_LESSTHAN OP_IF OP_0 OP_ELSE <128> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <128> OP_LESSTHAN OP_IF OP_0 OP_ELSE <128> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <128> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <64> OP_LESSTHAN OP_IF OP_0 OP_ELSE <64> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <64> OP_LESSTHAN OP_IF OP_0 OP_ELSE <64> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <64> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <32> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <32> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32> OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF <32> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_16 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_16 OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF OP_16 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_8 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_8 OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF OP_8 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_4 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_4 OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF OP_4 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_2 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_2 OP_SUB OP_1 OP_ENDIF OP_ROT OP_NUMNOTEQUAL OP_IF OP_2 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_NUMNOTEQUAL OP_IF OP_FROMALTSTACK OP_1 OP_ADD OP_ELSE OP_FROMALTSTACK OP_ENDIF
OP_AND: OP_0 OP_TOALTSTACK OP_DUP <1073741824> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1073741824> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1073741824> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1073741824> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <1073741824> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <536870912> OP_LESSTHAN OP_IF OP_0 OP_ELSE <536870912> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <536870912> OP_LESSTHAN OP_IF OP_0 OP_ELSE <536870912> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <536870912> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <268435456> OP_LESSTHAN OP_IF OP_0 OP_ELSE <268435456> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <268435456> OP_LESSTHAN OP_IF OP_0 OP_ELSE <268435456> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <268435456> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <134217728> OP_LESSTHAN OP_IF OP_0 OP_ELSE <134217728> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <134217728> OP_LESSTHAN OP_IF OP_0 OP_ELSE <134217728> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <134217728> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <67108864> OP_LESSTHAN OP_IF OP_0 OP_ELSE <67108864> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <67108864> OP_LESSTHAN OP_IF OP_0 OP_ELSE <67108864> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <67108864> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <33554432> OP_LESSTHAN OP_IF OP_0 OP_ELSE <33554432> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <33554432> OP_LESSTHAN OP_IF OP_0 OP_ELSE <33554432> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <33554432> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <16777216> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16777216> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <16777216> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16777216> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <16777216> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <8388608> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8388608> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <8388608> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8388608> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <8388608> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <4194304> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4194304> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <4194304> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4194304> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <4194304> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <2097152> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2097152> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <2097152> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2097152> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <2097152> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <1048576> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1048576> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1048576> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1048576> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <1048576> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <524288> OP_LESSTHAN OP_IF OP_0 OP_ELSE <524288> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <524288> OP_LESSTHAN OP_IF OP_0 OP_ELSE <524288> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <524288> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <262144> OP_LESSTHAN OP_IF OP_0 OP_ELSE <262144> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <262144> OP_LESSTHAN OP_IF OP_0 OP_ELSE <262144> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <262144> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <131072> OP_LESSTHAN OP_IF OP_0 OP_ELSE <131072> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <131072> OP_LESSTHAN OP_IF OP_0 OP_ELSE <131072> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <131072> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <65536> OP_LESSTHAN OP_IF OP_0 OP_ELSE <65536> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <65536> OP_LESSTHAN OP_IF OP_0 OP_ELSE <65536> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <65536> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <32768> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32768> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <32768> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32768> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <32768> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <16384> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16384> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <16384> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16384> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <16384> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <8192> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8192> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <8192> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8192> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <8192> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <4096> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4096> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <4096> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4096> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <4096> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <2048> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2048> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <2048> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2048> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <2048> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <1024> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1024> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1024> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1024> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <1024> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <512> OP_LESSTHAN OP_IF OP_0 OP_ELSE <512> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <512> OP_LESSTHAN OP_IF OP_0 OP_ELSE <512> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <512> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <256> OP_LESSTHAN OP_IF OP_0 OP_ELSE <256> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <256> OP_LESSTHAN OP_IF OP_0 OP_ELSE <256> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <256> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <128> OP_LESSTHAN OP_IF OP_0 OP_ELSE <128> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <128> OP_LESSTHAN OP_IF OP_0 OP_ELSE <128> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <128> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <64> OP_LESSTHAN OP_IF OP_0 OP_ELSE <64> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <64> OP_LESSTHAN OP_IF OP_0 OP_ELSE <64> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <64> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <32> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <32> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF <32> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_16 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_16 OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF OP_16 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_8 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_8 OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF OP_8 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_4 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_4 OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF OP_4 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_2 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_2 OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLAND OP_IF OP_2 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_BOOLAND OP_IF OP_FROMALTSTACK OP_1 OP_ADD OP_ELSE OP_FROMALTSTACK OP_ENDIF
OP_OR: OP_0 OP_TOALTSTACK OP_DUP <1073741824> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1073741824> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1073741824> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1073741824> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <1073741824> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <536870912> OP_LESSTHAN OP_IF OP_0 OP_ELSE <536870912> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <536870912> OP_LESSTHAN OP_IF OP_0 OP_ELSE <536870912> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <536870912> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <268435456> OP_LESSTHAN OP_IF OP_0 OP_ELSE <268435456> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <268435456> OP_LESSTHAN OP_IF OP_0 OP_ELSE <268435456> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <268435456> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <134217728> OP_LESSTHAN OP_IF OP_0 OP_ELSE <134217728> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <134217728> OP_LESSTHAN OP_IF OP_0 OP_ELSE <134217728> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <134217728> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <67108864> OP_LESSTHAN OP_IF OP_0 OP_ELSE <67108864> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <67108864> OP_LESSTHAN OP_IF OP_0 OP_ELSE <67108864> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <67108864> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <33554432> OP_LESSTHAN OP_IF OP_0 OP_ELSE <33554432> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <33554432> OP_LESSTHAN OP_IF OP_0 OP_ELSE <33554432> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <33554432> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <16777216> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16777216> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <16777216> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16777216> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <16777216> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <8388608> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8388608> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <8388608> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8388608> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <8388608> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <4194304> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4194304> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <4194304> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4194304> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <4194304> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <2097152> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2097152> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <2097152> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2097152> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <2097152> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <1048576> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1048576> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1048576> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1048576> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <1048576> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <524288> OP_LESSTHAN OP_IF OP_0 OP_ELSE <524288> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <524288> OP_LESSTHAN OP_IF OP_0 OP_ELSE <524288> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <524288> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <262144> OP_LESSTHAN OP_IF OP_0 OP_ELSE <262144> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <262144> OP_LESSTHAN OP_IF OP_0 OP_ELSE <262144> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <262144> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <131072> OP_LESSTHAN OP_IF OP_0 OP_ELSE <131072> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <131072> OP_LESSTHAN OP_IF OP_0 OP_ELSE <131072> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <131072> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <65536> OP_LESSTHAN OP_IF OP_0 OP_ELSE <65536> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <65536> OP_LESSTHAN OP_IF OP_0 OP_ELSE <65536> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <65536> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <32768> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32768> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <32768> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32768> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <32768> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <16384> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16384> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <16384> OP_LESSTHAN OP_IF OP_0 OP_ELSE <16384> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <16384> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <8192> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8192> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <8192> OP_LESSTHAN OP_IF OP_0 OP_ELSE <8192> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <8192> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <4096> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4096> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <4096> OP_LESSTHAN OP_IF OP_0 OP_ELSE <4096> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <4096> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <2048> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2048> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <2048> OP_LESSTHAN OP_IF OP_0 OP_ELSE <2048> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <2048> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <1024> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1024> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <1024> OP_LESSTHAN OP_IF OP_0 OP_ELSE <1024> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <1024> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <512> OP_LESSTHAN OP_IF OP_0 OP_ELSE <512> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <512> OP_LESSTHAN OP_IF OP_0 OP_ELSE <512> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <512> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <256> OP_LESSTHAN OP_IF OP_0 OP_ELSE <256> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <256> OP_LESSTHAN OP_IF OP_0 OP_ELSE <256> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <256> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <128> OP_LESSTHAN OP_IF OP_0 OP_ELSE <128> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <128> OP_LESSTHAN OP_IF OP_0 OP_ELSE <128> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <128> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <64> OP_LESSTHAN OP_IF OP_0 OP_ELSE <64> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <64> OP_LESSTHAN OP_IF OP_0 OP_ELSE <64> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <64> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP <32> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32> OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP <32> OP_LESSTHAN OP_IF OP_0 OP_ELSE <32> OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF <32> OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_16 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_16 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_16 OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF OP_16 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_8 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_8 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_8 OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF OP_8 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_4 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_4 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_4 OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF OP_4 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_2 OP_SUB OP_1 OP_ENDIF OP_ROT OP_DUP OP_2 OP_LESSTHAN OP_IF OP_0 OP_ELSE OP_2 OP_SUB OP_1 OP_ENDIF OP_ROT OP_BOOLOR OP_IF OP_2 OP_FROMALTSTACK OP_ADD OP_TOALTSTACK OP_ENDIF OP_BOOLOR OP_IF OP_FROMALTSTACK OP_1 OP_ADD OP_ELSE OP_FROMALTSTACK OP_ENDIF
For OP_LSHIFT, you can left shift by 1 by multiplying by two: So to left shift by 3, for example, you just do 3 left shifts by 1: OP_DUP OP_ADD
OP_DUP OP_ADD
OP_DUP OP_ADD
If your number is greater than or equal to 2^30, however, you need to first clear the topbit before doing the shift, which can be accomplished by the following: // start clear top bit <1073741824> OP_2DUP OP_GREATERTHANOREQUAL OP_IF OP_SUB // subtract 2^30 OP_ELSE OP_DROP // ignore 2^30 and leave the number unmodified OP_ENDIF // end clear top bit
OP_DUP OP_ADD
|
|
|
In support of the BIP to enable OP_CAT, we challenged ourselves to implement hashes that could use multiple computed stack items as a preimage without OP_CAT. In the end, we implemented both SHA256 and BLAKE3: You can view the source + test out both hashes here: https://bitide.qedprotocol.com/?importProject=https%3A%2F%2Fbtcscripts.qed.run%2Fexamples%2Fhash_demo.json&openFile=scripts%2Fblake3_demo_1.js See the video above for usage. For both scripts, the inputs are represented as U32s grouped as <top bit> <lower 31 bits>. For example, if you want to compute the blake3 hash of the data 'c85b298792a5b8d0082c2ed839c3830bcd4a6f18b827f6ce5ecf8838b1917e6a78ac10ef3e97660 c3529ca929dbbb207f6cb9279c49a4df29f67201776962c7c', you first split it the input data into U32s and get the following items on the stack: OP_1 <120150984> OP_1 <1354278290> OP_1 <1479420936> OP_0 <193184569> OP_0 <409946829> OP_1 <1324754872> OP_0 <948490078> OP_0 <1786679729> OP_1 <1863363704> OP_0 <208049982> OP_1 <315238709> OP_0 <129153949> OP_0 <2039663606> OP_1 <1917688516> OP_0 <387999647> OP_0 <2083296886>
To do this automatically, just use: var cfg = sch.getLimbsConfig([1, 31]); // define a U32 integer stack group which has two limbs: <top bit> <lower 31 bits> var testInputs = sch.hexToU32Array('c85b298792a5b8d0082c2ed839c3830bcd4a6f18b827f6ce5ecf8838b1917e6a78ac10ef3e97660c3529ca929dbbb207f6cb9279c49a4df29f67201776962c7c', false); testInputs.forEach(x => { b.constants(cfg.splitParts(x)); });
b.OP_HASH_U32_BLAKE3_256(testInputs.length); // 16 = number of uint32s in preimage
The result of OP_HASH_U32_BLAKE3_256 is the following stack: OP_1 <674114300> OP_1 <1860412368> OP_1 <642631595> OP_0 <1768883315> OP_0 <1529469502> OP_1 <1658424509> OP_0 <1384360961> OP_0 <918971398>
Which is the U32 representation of fc2a2ea8d0a3e3eeabc74da673046f693eda295bbd8cd9e201ac83520664c636. And in fact blake3("c85b298792a5b8d0082c2ed839c3830bcd4a6f18b827f6ce5ecf8838b1917e6a78ac10ef3e97660 c3529ca929dbbb207f6cb9279c49a4df29f67201776962c7c") = fc2a2ea8d0a3e3eeabc74da673046f693eda295bbd8cd9e201ac83520664c636! The scripts are chonkers but do work on the latest version of Bitcoin Core (if you want to test it on a real node, docker pull the latest version of BitIDE and replace bitide.qedprotocol.com in the link above with localhost:1337). If you like these kind of impossible ports, show some love by supporting the long over due proposals to re-enable useful features on Bitcoin and make these scripts obsolete!
|
|
|
Password Recovery When it comes to any puzzles, there is for example this puzzle: https://bitcointalk.org/index.php?topic=5469657.0And then, people may think, that SHA-1 was used, to create them, and make TapScripts, unspendable by key: 1) OP_SHA1 <3045ae6fc8422f64ed579528d38120eae12196d5> OP_EQUAL 2) OP_SHA1 <bd71344799d5c7fcdc45b59fa3b9ab8f6a948bc5> OP_EQUAL 3) OP_SHA1 <c49d360886e704936a6678e1139d26b7819f7e90> OP_EQUAL 4) OP_SHA1 <a335926aa319a27a1d00896a6773a4827acdac73> OP_EQUAL 5) OP_SHA1 <d09e8800291cb85396cc6717393284aaa0da64ba> OP_EQUAL Imagine, how the person solving that would feel, if it would turn out, that those coins are unspendable, because of the wrong endianness. So, instead of using unspendable key-path, it can be just "multisig behind all interested parties". It is possible to start with a single key, just like the creator of the famous puzzle, where keys #120 and #125 are sweeped, but nobody knows, if those keys are really broken, or if the author just moved those funds. And if you have any kind of reward, then by using multisig, you can start with a single key, and then move those coins by key, to combine the same rewards into bigger coins. Which means, if Alice and Bob sent funds to some different keys, with the same attached TapScript, then they could move them to a multisig, and a TapScript. And that move may be more attractive to the puzzle solver, because having single coin is cheaper to move, than having thousands of small deposits (not to mention address reuse, which is a bad practice, and should be avoided). Recursive Covenants + Trustless peg-in/peg-out for layer 2s If you have more than one person, behind some coin, then it may be possible, that all of them will be online. In that case, there is no reason to use expensive TapScript path, and reveal the whole covenant on-chain. The group, which wants to be detached, can just propose a withdrawal transaction, and collect all signatures from all parties, and then it will look the same, as if everything would be owned by a single user. To sum up: I cannot see a reason, why not to use multisig. If you are alone, then it gives you a chance to experiment with TapScript, without trapping your coins in unspendable paths. If there are at least two people (for example: Alice tells Bob that she will pay for Password Recovery), then, 2-of-2 multisig is applicable. If there are more than two people, then N-of-N multisig is applicable in a general case. And then, for example if Bob cannot provide the password, Alice can say: "well, you tried cracking it for 10 years, and you failed, it is now useless information for me, so I sweep my funds, you don't have to work longer on that". And if Bob agrees, then it is at least possible for Alice to get her funds back. But if it is behind TapScript-only, then it may be unspendable forever. Also, there are obvious mistakes possible, for example wrong endianness, and then, key-path can be used to fix those cases, instead of losing coins forever. So, instead of using unspendable key-path, it can be just "multisig behind all interested parties".
Totally agree! I think the rule of thumb is: use a multisig if you know the interested parties ahead of time, otherwise use NUMS. For the example of the puzzle/hash cracking, one may have to spend a significant portion of time/compute to crack the hash, so if they original challenge holder can just transfer away the funds at will, it may be a disincentive to commit resources to the problem. In the case of the layer 2, I would push back, however. To be secure, the multisig should be controlled by the owners of layer 2 wrapped BTC so they can reclaim the BTC on Layer 1 back whenever they like. This is impossible if the layer 2 BTC is transferrable. Consider the following scenario: 3 bitcoin holders each bridge 10 BTC to layer 2, locking a total of 30 BTC in a multisig (lets call the set of keys in the multisig K), minting a total 30 l2BTC on the layer 2. Since the K should proportionally represent owners of l2BTC, they should each control a key in the multisig. The 3 original users then purchase NFTs on the L2 with their l2BTC on an L2-DEX, spending all 30 BTC. Now the original set K does not represent the token holders and is instead controlled by a group which owns no l2BTC.
|
|
|
For situations where a multisig is appropriate Could you give any example, where it is not? 1. Password Recovery Let's say I want to crack a sha256 password hash (your own personal password and not someone else's, of course). If know the hash is 5bf01f36fa15d5ccf2dea7a53c777426d559a9a8d1384e58bc8d3dc423cd2f12, I could offer a reward in bitcoin for anyone who can provide the preimage to the password with the following script: OP_SHA256 <5bf01f36fa15d5ccf2dea7a53c777426d559a9a8d1384e58bc8d3dc423cd2f12> OP_EQUAL
You can try it out if you like on testnet (the password is supersecretpassword) 2. Recursive Covenants + Trustless peg-in/peg-out for layer 2s Imagine we have a layer 2 which posts a withdrawals tree of the chain to bitcoin, and we want to allow users to trustlessly withdraw their bitcoins from layer 2. When block producers submit a block they spend and existing block script which has two outputs: 1. an output to a withdrawal UTXO script which can be spent by the users who withdrew funds from layer 2 back to layer 1 in the most recent block (includes a withdrawal tree merkle root) 2. a new block UTXO for the next block (recurse) The withdrawal script can only be spent by spending a recursive covenant which includes a delta merkle proof proving the validity of the spend of one of the withdrawals and an additional recursive covenant that creates a new withdrawal script with the updated withdrawal tree root (the withdrawal made is set to the null value so you can't spend a withdrawal more than once). The locked BTC in the layer 2 block UTXO can only be sent to a script which publishes a new block (1 output) or a withdrawal script which allows users to withdraw a portion of the BTC and sends the rest to a new script with the updated merkle root (2 outputs). In our withdrawal script, we verify a merkle proof which links the previously submitted state root/withdrawals tree root with a spender: <0x8fe1e5f7bc9333914565f011a63942d988c88b00547b35af859635b00cbbc64c> // old root, must be this value as enforced by the block UTXO covenant <0x7163998f26fec2e57db7413d706d30e7b9f14e13b416217160221ff05690fb65> // new root after spending the withdrawal and removing it from the withdrawals tree
// merkle proof siblings <0x2f0935c2963ead8b3be0ee5d4d4dcb3af23646c6bbfc330e41e90a47ee8cf7f7> // sibling at level 14 <0xeac71276dd976b550cace2fb1097ad5d296193fea0359202ca4899b398ab2436> // sibling at level 13 <0x2c7011733c31c9c58e0d5cbe40be77c714a4b77b281ffd72155276af21452e24> // sibling at level 12 <0x5cc411ccc9b0ce4704798316824afffbbeb724d7fb06701bf7c57f1fa122102f> // sibling at level 11 <0x485a020e9ce6f948b88528bc38ac34838283bd4a001db1f99b84cbe87ebe3e99> // sibling at level 10 <0x885fb789bdd39eee523ade57bedba8fa308b9014c910d6db04b779732139c5b7> // sibling at level 9 <0x8b4578b4daaa30f78eaa2f5537142c9fe277a87fc4e8c5dd872ab95524d34c48> // sibling at level 8 <0xdcd5818eaddf2de1a4fd8792664403a1b1e24779baf3bfac02f169ae63b46d95> // sibling at level 7 <0x7900bfb52e43f1c0b93a87e4b42bc652a1de0c6e72becc37a4f1d26a3eac42a6> // sibling at level 6 <0x2013541c218b99def8301bb9b283f3696605e39a267e757e61692e47623bebdb> // sibling at level 5 <0x9e5a86f32a7231309e3f4bc44473a181b3482352acc8e332d10b493a8acca77c> // sibling at level 4 <0xca67e1b7055afe377bd9fb285335a3685472b1c08f94cf133481320b0fe63653> // sibling at level 3 <0xf464a8d91ca7029a4b88483b7d778403c310c2eaabf46a905874343f975b49a0> // sibling at level 2 <0xaa6ef54b7988700bbcffcaf327be3ade37a68573e9fd6a498a00600059644a28> //sibling at leaf level
<999> // index of the withdrawal leaf we are spending with in the withdrawals tree
// recursive covenant inputs... <0x3905000000000000> // 8 byte spend amount (1337) <0xb4a2ef4141dfdedc3b548222b11fcf90bf81782ed6bf998b6552ab08978b2ce6> // spender OP_2DUP OP_CAT OP_SHA256 // compute the withdrawal hash -> 0xeac7f4e4689862aa7baf72c1673a48a66561ab222eb6a6d8af38c32393265d90 OP_TOALTSTACK // move the withdrawal hash to the alt stack for later // the rest of the recursive covenant code
// now only the merkle roots + siblings + index remains in the stack OP_FROMALTSTACK // old leaf value computed earlier (withdrawal hash) <0x0000000000000000000000000000000000000000000000000000000000000000>// new value OP_ROT // move the index to the top of the stack
// start decompose the index into bits // we decompose the number into bits which are stored on the alt stack <8192> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF <4096> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF <2048> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF <1024> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF <512> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF <256> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF <128> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF <64> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF <32> OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF OP_16 OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF OP_8 OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF OP_4 OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF OP_2 OP_2DUP OP_GREATERTHANOREQUAL OP_DUP OP_TOALTSTACK OP_DUP OP_TOALTSTACK OP_IF OP_SUB OP_ELSE OP_DROP OP_ENDIF OP_DUP OP_TOALTSTACK OP_TOALTSTACK
// end decompose the index into bits
// now the lowest bit of the index is on the alt stack
// compute old and new merkle roots OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
OP_ROT OP_ROT OP_OVER OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute old merkle path at level OP_ROT OP_ROT OP_FROMALTSTACK OP_ROLL OP_CAT OP_SHA256 // compute new merkle path at level
// end compute old and new merkle roots
Now we just check the old and new roots from the inputs to make sure the match the computed ones (ie. proof that the withdrawal exists in the tree, and that the merkle tree with merkle root new root has all the same leaves as old tree, except for the leaf at the specified index that has just been spent (and has been nulled out): /*
now the stack is as follows:
<old merkle root> // guarenteed correct via the covenant <new merkle root> // attested by the spender
<computed old merkle root> // computed from the index/siblings/withdrawal hash value <computed new merkle root> // computed from the index/siblings/nulled out value
*/
OP_ROT OP_EQUALVERIFY // check that the attested new merkle root is a copy of the old tree with the spent leaf nulled out
|
|
|
currently we just use a "Nothing Up My Sleeve" point which no one knows the private key of You should not use that, unless it is strictly necessary. It is better to pick a public key, that is just N-of-N multisig of everyone involved. In this way, there is always a chance to spend by key (and make it cheaper) if everyone agrees. In general, Taproot addresses should be "always spendable by key, and sometimes spendable by key, and by TapScript". For situations where a multisig is appropriate
|
|
|
I see this is not mobile friendly 😂 , but this is great to see people are actually developing something useful rather than trying to spam the network for more money.
Just wanted to tell you, fantastic work, amazing and thank you. Hope you could add some ECC related functions to have things in one place. 🤭
Btw, you founded QED? Any web address for it? Oh I saw it on your profile.
No plans for a mobile version (don't code on your phone haha), but more features on the way, namely: 1. Export standalone bitcoinjs-lib code in the TapScript runner (so you can see how to perform all the steps programmatically as well) 2. Support for OP_CHECKSIG/other sig related stuff + basic wallet/key manager 3. Option to pay with keypath rather than script in the TapScript runner (currently we just use a "Nothing Up My Sleeve" point which no one knows the private key of) 4. Support for Liquid
|
|
|
I'm looking to create a Bitcoin tapscript transaction, but I can't find an example or a tutorial that demonstrates how to do this. When I was building on Ethereum it was easy because there's a lot of tutorials about how to create a custom ERC-20 or ERC-721. I understand that comparing Ethereum to Bitcoin is like comparing apples to oranges. Bitcoin is designed to be a store of value while Ethereum is a platform designed to run code.
Still though... I want to practice writing tapscript transactions on Bitcoin. Can someone provide a code example or a tutorial about how to actually create a tapscript transaction?
Just to be clear, when I say a tapscript transaction, I mean constructing a UTXO that contains a script spending path. That means a taproot transaction that contains a merkle root with a taptree where spending from this UTXO means solving a logic condition in one of the tapleafs.
I'm eager to delve into Bitcoin tapscript transactions, but I'm struggling to find an example or tutorial guiding me through the process. When working with Ethereum, crafting custom ERC-20 or ERC-721 tokens was straightforward due to the abundance of tutorials available. I recognize the inherent differences between Bitcoin and Ethereum—Bitcoin as a store of value and Ethereum as a code-running platform. Nevertheless, my curiosity persists, and I'm determined to practice tapscript transactions on Bitcoin. Could someone kindly share a code example or direct me to a tutorial illustrating the creation of a tapscript transaction? To clarify, I'm specifically interested in constructing a UTXO with a script spending path—a taproot transaction featuring a merkle root with a taptree. The goal is to enable spending from this UTXO by satisfying a logic condition within one of the tapleafs. https://www.aoxapps.com/mobile-app-development-companyCheck out https://www.youtube.com/watch?v=ixHVnvq4S7g, this goes step by step through the full flow from 0 to p2tr via script spending path (also helps you setup a local testnet + block explorer).
|
|
|
Is BitIDE open source?
Cleaning up the source and adding some tests, will be open sourced this week =) Will appreciate the source. But is the real testnet version of this available? Yep! BitIDE works with regtest, testnet and mainnet. To fund and unlock a script UTXO on the official Bitcoin testnet, just chose "Testnet" in the tapscript executor window and follow the steps below: Note that Fund via RPC only works with regtest (you can't just mint testnet tBTC at will), so for step two you need to either faucet the address with a testnet faucet or send from your testnet wallet before clicking "Check for UTXOs"
|
|
|
Great work.
Though I'm not sure how you'll convince 3rd parties to use this.
Maybe if you go on X/Twitter you might be able to convince some Ordinals folks to use your own technology.
Haha yep, in the works! Also partnering with some larger zk projects to help promote the standard. To help the transition, will also open source a zk rollup that supports transfers/trading/swaps/pay to zkp.
|
|
|
Is BitIDE open source?
Cleaning up the source and adding some tests, will be open sourced this week =)
|
|
|
Hey all, I have been thinking a lot about the issue of ordinal spam and growing demand for extending the security of bitcoin to other use cases. It seems the community is split on support for ordinals, and the only way forward is to find a solution which gets rid of the spam while letting people still play with tokens on bitcoin. To resolve this, I propose L2Ordinals, a zero knowledge proof protocol which rolls up all the 1000s of ordinal transactions flooding the mempool into a single 300 byte proof which is verified by an indexer: In addition to cutting down on ordinal spam, this solution still provides the same security that standard ordinal based tokens have, while also extending the security model to arbitrary computation (anything you can write in a zk circuit, ex. zkVM): - All token transfers are PROVED by the ZKP and VERIFIED by the indexer (just as BRC-20 tokens are verified by the indexer)
- Sequenced by Bitcoin
- To compute the current layer 2 network state, all you have to do is startup a bitcoin full node + indexer and playback all the blocks from genesis
- State transitions are verified by the indexer to ensure proper sequencing (ex. enforce end state root of last proof is the start state of next proof)
There are some implementation details left out that you can checkout at: https://l2o.io/docs/l2o-a/operations/blockIf anyone else wants to help work on the indexer/has any ideas, feel free to shoot me a DM on twitter @cmpeq.
|
|
|
You can make the outputs 0. Not only that. You can also hide your scripts behind a TapScript, and then spend by key, if your TapScript will turn out to be unspendable or expensive. Great idea, we will also added support for key paths in the next version! In the meantime, for development purposes it shouldn't be an issue if you are using the docker image with bundled regtest + explorer and use Fund via RPC (regtest btc is free ), as clicking the button first runs generatetoaddress to mine 50 btc to the default wallet, and then transfers 1 BTC to the P2TR address (see screenshot below).
|
|
|
Hey all, added docker image for offline development, integration with local testnet (regtest), a block explorer and and a GUI that walks you through how to perform a pay to tapscript (script path) transaction (I saw a lot of people have been asking about this on the forum, so hope this helps). Grab the new version and start a new local testnet with a one liner: docker run -p 1337:1337 -it --rm qedprotocol/bitide:latest
Also shot a quick tutorial video for anyone that wants to get started with TapScript: Edit:If you want to use bitcoin-cli with your testnet, just change the docker command to: docker run -p 1337:1337 -p 18443:18443 -it --rm qedprotocol/bitide:latest
|
|
|
But they will always claim that their network has higher transaction throughput and therefore "scales", but how do we define "scale". Higher throughput but sacrifices decentralization? That's not scaling. It actually scales the network down, reducing node count, and therefore centralizing the network.
Exactly. With one caveat, if we can verify zero knowledge proofs and merkle proofs in bitcoin script, can process millions of transactions in a single uxto without sacrificing and scale, no trade offs, just proof of math (constant size proof -> proves arbitrary number of transactions -> user proves balance via merkle proof -> unlock uxto).
|
|
|
It looks good, but there doesn't seem to be a desktop version. If this is using a JS framework, you know, like React or Angular or Vue or like that, you can just slap Electron on it and you'll be good to go on all platforms.
Maybe you can add a feature where a the compiled script can run on testnet if you deposit a small amount of BTC for the transaction fee. You can make the outputs 0.
Great idea! will definitely add an offline electron version in the next release. Also right now we are working on a 1-liner that spins up a clean regtest network in a docker container with funded wallets and automining so you don't have to mess around with faucets, but testnet integration also makes a lot of sense.
|
|
|
|