|
| 1 | +# Miniscript Extensions: |
| 2 | + |
| 3 | +Extensions allow users to extend miniscript to have new leaf nodes. This document lists |
| 4 | +extensions implemented for elements-miniscript with the tapscript opcodes. Users can |
| 5 | +also implement custom extensions using [`Extension`] trait. |
| 6 | + |
| 7 | +# Value Arithmetic extensions (`NumExpr`) |
| 8 | + |
| 9 | +- Pushes single singed 64 bit LE number on stack top. Since these expressions push a 8 byte number, it does not directly |
| 10 | +fit in the miniscript model. These are used in fragments in one of the comparison fragment listed in the next section. |
| 11 | +- All of introspection opcodes explicitly assert the amount is explicit. |
| 12 | +- This will abort when |
| 13 | + - Any of operations are on confidential amounts. The Null case is automatically converted to explicit zero. |
| 14 | + - Supplied index is out of bounds. |
| 15 | + - Any of the operations overflow. Refer to tapscript [opcodes](https://github.com/ElementsProject/elements/blob/master/doc/tapscript_opcodes.md) spec for overflow specification |
| 16 | + |
| 17 | +Name | Script |
| 18 | +--- | --- |
| 19 | +i(i64 number) | `8-byte-LE-push of <i>` |
| 20 | +curr_inp_v | `INSPECTCURRENTINPUTINDEX INPSECTINPUTVALUE <1> EQUALVERIFY` |
| 21 | +inp_v(i) | `i INPSECTINPUTVALUE <1> EQUALVERIFY` |
| 22 | +out_v(i) | `i INPSECTOUTPUTVALUE <1> EQUALVERIFY` |
| 23 | +inp_issue_v(i) | `i OP_INSPECTINPUTISSUANCE DROP DROP <1> EQUALVERIFY NIP NIP` |
| 24 | +inp_reissue_v(i) | `i OP_INSPECTINPUTISSUANCE DROP DROP DROP DROP <1> EQUALVERIFY` |
| 25 | +bitinv(x) | `[X] INVERT` |
| 26 | +neg(x) | `[X] NEG64 <1> EQUALVERIFY` |
| 27 | +add(x,y) | `[X] [Y] ADD64 <1> EQUALVERIFY` |
| 28 | +sub(x,y) | `[X] [Y] SUB64 <1> EQUALVERIFY` |
| 29 | +mul(x,y) | `[X] [Y] MUL64 <1> EQUALVERIFY` |
| 30 | +div(x,y) | `[X] [Y] DIV64 <1> EQUALVERIFY NIP` |
| 31 | +mod(x,y) | `[X] [Y] DIV64 <1> EQUALVERIFY DROP` |
| 32 | +bitand(x,y) | `[X] [Y] AND` |
| 33 | +bitor(x,y) | `[X] [Y] OR (cannot fail)` |
| 34 | +bitxor(x,y) | `[X] [Y] XOR (cannot fail)` |
| 35 | + |
| 36 | + |
| 37 | +- The division operation pushes the quotient(a//b) such that the remainder a%b (must be non-negative and less than |b|). |
| 38 | +- neg(a) returns -a, whereas bitinv(a) returns ~a. |
| 39 | + |
| 40 | +## Comparison extensions |
| 41 | + |
| 42 | +As mentioned earlier, `NumExpr` directly does not fit in the miniscript model as it pushes a 8 byte computation result. |
| 43 | +To use these with miniscript fragments, we can use them inside comparison extensions. These comparison are of type `Bzdu`. |
| 44 | + |
| 45 | +Name | Script |
| 46 | +--- | --- |
| 47 | +num_eq(NumExpr_X,NumExpr_Y) | `[NumExpr_X] [NumExpr_Y] EQUAL64` |
| 48 | +le(NumExpr_X,NumExpr_Y) | `[NumExpr_X] [NumExpr_Y] LESSTHAN64` |
| 49 | +ge(NumExpr_X,NumExpr_Y) | `[NumExpr_X] [NumExpr_Y] GREATERTHAN64` |
| 50 | +leq(NumExpr_X,NumExpr_Y) | `[NumExpr_X] [NumExpr_Y] LESSTHANOREQUAL64` |
| 51 | +geq(NumExpr_X,NumExpr_Y) | `[NumExpr_X] [NumExpr_Y] GREATERTHANOREQUAL64` |
| 52 | + |
| 53 | +- For example, `num_eq(inp_v(1),mul(curr_inp_v,20))` represents second input value is the multiplication of |
| 54 | +current input value and fourth output value. This would abort if any of the values are confidential. |
| 55 | + |
| 56 | +### Tx Value introspection |
| 57 | + |
| 58 | +### AssetExpr |
| 59 | + |
| 60 | +- pushes a 32 byte asset + 1 byte prefix on stack top. These operations also support confidential assets. |
| 61 | +- This will abort when |
| 62 | + - Supplied index is out of bounds. |
| 63 | + |
| 64 | +Name | Script |
| 65 | +--- | --- |
| 66 | +`asset`(33 byte hex) | `[32-byte comm] [1 byte pref]` of this asset |
| 67 | +curr_inp_asset | `PUSHCURRENTINPUTINDEX INPSECTINPUTASSET` |
| 68 | +inp_asset(i) | `i INPSECTINPUTASSET` |
| 69 | +out_asset(i) | `i INPSECTOUTPUTASSET` |
| 70 | + |
| 71 | +### ValueExpr |
| 72 | + |
| 73 | +- pushes a 32 byte value(8-byte-LE value if explicit) + 1 byte prefix on stack top. These operations also support confidential values. |
| 74 | +- This will abort when |
| 75 | + - Supplied index is out of bounds. |
| 76 | + |
| 77 | +Name | Script |
| 78 | +--- | --- |
| 79 | +`value`(33/9 byte hex) | `[32-byte comm/8 byte LE] [1 byte pref]` of this Value |
| 80 | +curr_inp_value | `PUSHCURRENTINPUTINDEX INPSECTINPUTVALUE` |
| 81 | +inp_value(i) | `i INPSECTINPUTVALUE` |
| 82 | +out_value(i) | `i INPSECTOUTPUTVALUE` |
| 83 | + |
| 84 | +### SpkExpr: Script PubKey Expression |
| 85 | + |
| 86 | +- Pushes a witness program + 1 byte witness version on stack top. |
| 87 | +- If the script pubkey is not a witness program. Push a sha256 hash of the script pubkey followed by -1 witness version |
| 88 | +- This will abort when |
| 89 | + - Supplied index is out of bounds. |
| 90 | + |
| 91 | +Name | Script |
| 92 | +--- | --- |
| 93 | +`spk`(script_hex) | `[program] [witness version]` of this spk (`<Sha2Hash(Script)> <-1>`) for legacy |
| 94 | +curr_inp_spk | `PUSHCURRENTINPUTINDEX INPSECTINPUTSCRIPTPUBKEY` |
| 95 | +inp_spk(i) | `i INPSECTINPUTSCRIPTPUBKEY` |
| 96 | +out_spk(i) | `i INPSECTOUTPUTASSETSCRIPTPUBKEY` |
| 97 | + |
| 98 | +## Introspection Operations |
| 99 | + |
| 100 | +- `ValueExpr`, `AssetExpr` and `SpkExpr` do not fit in to the miniscript model. To use these |
| 101 | +in miniscript, we can use the below defined introspection operations. These are of type `Bzdu` |
| 102 | +- Reasoning the safety of covenants using introspection is not possible for miniscript to do as |
| 103 | +from point of view of miniscript these are anyone can spend without any signatures. However, in |
| 104 | +practice these are usually secured via cross input transactional logic beyond the current executing script. |
| 105 | + |
| 106 | +Name | Script |
| 107 | +--- | --- |
| 108 | +is_exp_asset(AssetExpr_X) | `[AssetExpr_X] <1> EQUAL NIP` |
| 109 | +is_exp_value(ValueExpr_X) | `[ValueExpr_X] <1> EQUAL NIP` |
| 110 | +asset_eq(AssetExpr_X,AssetExpr_Y) | `[AssetExpr_X] TOALTSTACK [AssetExpr_Y] FROMALTSTACK EQUAL TOALTSTACK EQUAL FROMALTSTACK BOOLAND` |
| 111 | +value_eq(ValueExpr_X,ValueExpr_Y) | `[ValueExpr_X] TOALTSTACK [ValueExpr_Y] FROMALTSTACK EQUAL TOALTSTACK EQUAL FROMALTSTACK BOOLAND` |
| 112 | +spk_eq(SpkExpr_X,SpkExpr_Y) | `[SpkExpr_X] TOALTSTACK [SpkExpr_Y] FROMALTSTACK EQUAL TOALTSTACK EQUAL FROMALTSTACK BOOLAND` |
| 113 | +curr_idx_eq(i) | `<i> PUSHCURRENTINPUTINDEX EQUAL` |
0 commit comments