<p>I think we first need to distinguish between the script stack <em>as an abstract concept</em> as it exists during script execution, and the initial stack <em>serialization</em> in the transaction input witness.</p>
<p>The stack, during execution, is a vector of vectors of bytes. For example, we could have a stack that consists of 3 vectors, the first being empty, the second being a single 0 byte, and the third consisting of 4 0xba bytes. We'll denote that as:</p>
<blockquote>
<p>{{}, {0x00}, {0xba, 0xba, 0xba, 0xba}}</p>
</blockquote>
<p>These would be serialized in the transaction input witness as {0x00, 0x01, 0x00, 0x04, 0xba, 0xba, 0xba, 0xba}. So when you're asking about 0x00, it depends on whether you're taking about the stack elements, or their serialization. An empty stack element is empty, length 0, no contents - but its serialization is a 0x00 byte.</p>
<p>Executing an <code>OP_0</code> (encoded as 0x00) pushes onto the stack a empty byte vector, so starting from the previous example, we'd get:</p>
<blockquote>
<p>{{}, {0x00}, {0xba, 0xba, 0xba, 0xba}, {}}</p>
</blockquote>
<p>The script <code>OP_3</code> (encoded as 0x53) pushes the 1-byte stack element {0x03} onto the stack:</p>
<blockquote>
<p>{{}, {0x00}, {0xba, 0xba, 0xba, 0xba}, {}, {0x03}}</p>
</blockquote>
<p>On the other hand, the script <code>&lt;0x00&gt;</code> (encoded itself as {0x01, 0x00} pushes the 1-byte value {0x00}:</p>
<blockquote>
<p>{{}, {0x00}, {0xba, 0xba, 0xba, 0xba}, {}, {0x03}, {0x00}}</p>
</blockquote>
<p>For the purpose of OP_CHECKSIG and OP_CHECKSIGADD, a signature equal to {} is special: this is the only &quot;invalid&quot; signature allowed. Any other signature stack element which doesn't actually verify correctly causes the script execution to abort immediately. An {} signature element simply causes a 0 (= {}) to be pushed onto the stack for OP_CHECKSIG, and no increment to occur for OP_CHECKSIGADD.</p>
<p>These rules do <em>not</em> apply to the stack element {0x00}, or any other value. The stack element has to be {} exactly. But again, that stack element can appear by being present in the witness stack, where it'd be serialized as {0x00}, or can be pushed using <code>OP_0</code> inside script (which is encoded as 0x00 as well).</p>

CC BY-SA 4.0
2023-11-25T03:06:23.907Z
Wow, what an answer, amazing. Have 2 questions. 1) `An {} signature element simply causes a 0 (= {}) to be pushed onto the stack for OP_CHECKSIG...`, is it more accurate to say ***empty vector*** instead of 0 since 0 can also mean to push literally zero like {0x00}? 2) `But again, that stack element can appear by being present in the witness stack, where it'd be serialized as {0x00}` by this you mean that the witness item is of length 0?
Cosmos
CC BY-SA 4.0
2023-11-25T03:21:09.187Z
Also, 3) If the witness stack have elements with the length of zero (0x00), it won't just ignore them but push empty vector ({}) onto the initial stack. For example, if the witness stack starts like `000000...` it will push three empty vectors ({}) onto the initial stack?
Cosmos
CC BY-SA 4.0
2023-11-25T03:56:12.350Z
(1) They're equivalent; an empty vector is how in the script language the number 0 is represented (as it's also what OP_0 pushed), so they can be used interchangeably. (2) Yes, the serialization of a 0-length stack element is the byte 0x00. (3) Indeed, empty stack elements are very much not ignored. The witness stack serialization {0x00, 0x00, 0x00} indeed represents an initial stack of 3 empty vectors.
Pieter Wuille
CC BY-SA 4.0
2023-11-25T12:00:46.433Z
For the first question. So how can I distinguish 0 in the case of `{}` and `{0x00}`? **Both represent 0.** For example, if someone says there must be a 0 on the stack, does that mean {} or {0x00}? Also, if it says, for example, that the opcode will push a 0 onto the stack or there must be a 0 on the stack for some opcode to pass, is it {} or {0x00} (since both are actually 0). From what I understand looking at what you wrote, it looks like 0 actually just represents the empty vector `{}`, but what is then the *TERM* for pushing 0 as {0x00} onto the stack  (if it exists)?
Cosmos
CC BY-SA 4.0
2023-11-25T12:10:05.357Z
Also, when it says **FALSE** (for example, "*opcode will push FALSE on the stack in order to...*" or "*must be FALSE on stack in order to opcode not invalidate script, otherwise....*"), does in Bitcoin it represent an empty vector (`{}`) on the stack or `{0x00}` on the stack, or both? I assume just the first one (`{}`). **For TRUE** I know that's `{0x01}`.
Cosmos
CC BY-SA 4.0
2023-11-25T12:37:10.447Z
False, 0, and empty vector are all the same thing. I don't think there is a common name for {0x00} as while it's indeed also treated as 0 in numeric context, it's not actually commonly used.
Pieter Wuille
CC BY-SA 4.0
2023-11-25T12:59:12.807Z
Okay, so `{0x00}` on the stack won't be threated as FALSE since FALSE is just an empty vector (`{}`)?
Cosmos
CC BY-SA 4.0
2023-11-25T13:05:37.173Z
Whenever a stack element is treated as a boolean (e.g for OP_BOOLAND), any byte vector that contains a nonzero byte is *treated* as "true", while others are *treated* as "false" (including {}, {0x00}, {0x00, 0x00}, ...) But when we say an opcode "pushes false", it is always {} because the shortest encoding is preferred.
Pieter Wuille
CC BY-SA 4.0
2023-11-25T13:10:48.087Z
That's the answer I was look for, thanks! Just one strange question. How does Bitcoin threat nothing ("air") on the stack. Also as FALSE or will fail the script execution? For example if some opcode require false on the stack, but it finds an empty stack?
Cosmos
CC BY-SA 4.0
2023-11-25T13:16:33.123Z
That's an error. Anything that needs more stack elements than are available causes script execution to abort and treat the transaction as invalid.
Pieter Wuille
CC BY-SA 4.0
2023-11-25T14:17:01.877Z
Just one question related to the **MINIMALIF** rule from the BIP342. It requires either exactly 1 as a top stack element (`{0x01}` as a top stack element) or 0 as a top stack element. Since 0 in Bitcoin, as you previously mentioned, always denotes/represents `{}`, then the `{}` must be the top stack element in this case, and not for example `{0x00}`, `{0x00, 0x00}`. Correct?
Cosmos
CC BY-SA 4.0
2023-11-25T14:23:53.170Z
Indeed, the MINIMALIF rule (consensus in tapscript, a standardness rule for other scripts) requires the input to an OP_IF or OP_NOTIF to be *exactly* {}, or exactly {0x01}.
Pieter Wuille
CC BY-SA 4.0
2023-11-25T14:29:54.513Z
Thanks for all the help!
Cosmos
CC BY-SA 4.0
2023-11-25T02:35:55.907Z
2023-11-25T02:35:55.907Z
Pieter Wuille
<p><strong>EDIT</strong>: Pieter Wuille gave an <a href="https://bitcoin.stackexchange.com/a/120616/146389">answer</a> (look at the comments) to the last situation (with <code>OP_CHECKSIG</code>). OP_CHECKSIG is pushing <code>0x00</code>.</p>
<blockquote>
<p>E.g. OP_0 pushes the empty vector, which represents the number 0 (to
numeric opcodesk).</p>
</blockquote>
<hr />
<hr />
<p>Probably the lowest-IQ question ever, but what does <em><strong>empty vector</strong></em> represent in Bitcoin? Is it a single byte <code>0x00</code> (value 0) or is it literally nothing (&quot;air&quot;) or maybe both depending on the situation?</p>
<p>In BIP342, the following is written for <code>OP_IF</code> and <code>OF_NOTIF</code> :</p>
<blockquote>
<p><strong>Consensus-enforced MINIMALIF</strong> The MINIMALIF rules, which are only a
standardness rule in P2WSH, are consensus enforced in tapscript. This
means that the input argument to the <code>OP_IF</code> and <code>OP_NOTIF</code> opcodes must
be either exactly 0 (the empty vector) or exactly 1 (the one-byte
vector with value 1).</p>
</blockquote>
<p>I assume that here <em><strong>empty vector</strong></em> represents literally byte <code>0x00</code> (value <code>0</code>) on the stack, thus it is not an &quot;air&quot; (nothing). I have that assumption because if the <em><strong>empty vector</strong></em> here represents an &quot;air&quot; (nothing) then it would require totally empty stack to perform these opcodes.</p>
<p>In the same BIP, for signature opcodes (OP_CHECKSIGADD, OP_CHECKSIGVERIFY and OP_CHECKSIG) and signature check it says that if the signature is an <em><strong>empty vector</strong></em> then different behaviors are performed than in pre-Taproot. I assume that here <em><strong>empty vector</strong></em> literally represents an &quot;air&quot;, i.e. the witness item with length 0.</p>
<p>At the end, in the BIP342, it writes that if the signature is an empty vector (&quot;air&quot;; witness item with the length 0), then <code>OP_CHECKSIG</code> will push an <em><strong>empty vector</strong></em> onto the stack and execution continues with the next opcode. I assume that the <em><strong>empty vector</strong></em> in the case of opcodes (<code>OP_CHECKSIG</code> in this case) also represent byte <code>0x00</code> (value 0), since there is no point to push literally nothing (&quot;air&quot;) onto the stack.</p>
<ol>
<li>Am I right or wrong? Does <em><strong>empty vector</strong></em> actually represents the (3) option from the first paragraph, thus in case of stack it represents <code>0x00</code> and in case of witness stack it represents item with the length of 0? If not, can you tell me what the <em><strong>empty vector</strong></em> represents.</li>
<li>Would a witness item of length 1 and value <code>0x00</code> also be considered an <em><strong>empty vector</strong></em> so that the signature check also would not be performed in the case of Tapscript?</li>
</ol>

<script><opcodes>
What is an "empty vector" in Bitcoin?
Cosmos
# What is an "empty vector" in Bitcoin?

(Asked by: username_0 on 2023-11-24)

**EDIT**: username_1 username_1 gave an [answer](https://bitcoin.stackexchange.com/a/120616/146389) (look at the comments) to the last situation (with `OP_CHECKSIG`). OP\_CHECKSIG is pushing `0x00`.

> E.g. OP\_0 pushes the empty vector, which represents the number 0 (to
> numeric opcodesk).

---

---

Probably the lowest-IQ question ever, but what does ***empty vector*** represent in Bitcoin? Is it a single byte `0x00` (value 0) or is it literally nothing ("air") or maybe both depending on the situation?

In BIP342, the following is written for `OP_IF` and `OF_NOTIF` :

> **Consensus-enforced MINIMALIF** The MINIMALIF rules, which are only a
> standardness rule in P2WSH, are consensus enforced in tapscript. This
> means that the input argument to the `OP_IF` and `OP_NOTIF` opcodes must
> be either exactly 0 (the empty vector) or exactly 1 (the one-byte
> vector with value 1).

I assume that here ***empty vector*** represents literally byte `0x00` (value `0`) on the stack, thus it is not an "air" (nothing). I have that assumption because if the ***empty vector*** here represents an "air" (nothing) then it would require totally empty stack to perform these opcodes.

In the same BIP, for signature opcodes (OP\_CHECKSIGADD, OP\_CHECKSIGVERIFY and OP\_CHECKSIG) and signature check it says that if the signature is an ***empty vector*** then different behaviors are performed than in pre-Taproot. I assume that here ***empty vector*** literally represents an "air", i.e. the witness item with length 0.

At the end, in the BIP342, it writes that if the signature is an empty vector ("air"; witness item with the length 0), then `OP_CHECKSIG` will push an ***empty vector*** onto the stack and execution continues with the next opcode. I assume that the ***empty vector*** in the case of opcodes (`OP_CHECKSIG` in this case) also represent byte `0x00` (value 0), since there is no point to push literally nothing ("air") onto the stack.

1. Am I right or wrong? Does ***empty vector*** actually represents the (3) option from the first paragraph, thus in case of stack it represents `0x00` and in case of witness stack it represents item with the length of 0? If not, can you tell me what the ***empty vector*** represents.
2. Would a witness item of length 1 and value `0x00` also be considered an ***empty vector*** so that the signature check also would not be performed in the case of Tapscript?

**Tags:** script, opcodes


---

## 1 answers

### Answer by username_1 on 2023-11-25. Score: 4 | Accepted answer

I think we first need to distinguish between the script stack *as an abstract concept* as it exists during script execution, and the initial stack *serialization* in the transaction input witness.

The stack, during execution, is a vector of vectors of bytes. For example, we could have a stack that consists of 3 vectors, the first being empty, the second being a single 0 byte, and the third consisting of 4 0xba bytes. We'll denote that as:

> {{}, {0x00}, {0xba, 0xba, 0xba, 0xba}}

These would be serialized in the transaction input witness as {0x00, 0x01, 0x00, 0x04, 0xba, 0xba, 0xba, 0xba}. So when you're asking about 0x00, it depends on whether you're taking about the stack elements, or their serialization. An empty stack element is empty, length 0, no contents - but its serialization is a 0x00 byte.

Executing an `OP_0` (encoded as 0x00) pushes onto the stack a empty byte vector, so starting from the previous example, we'd get:

> {{}, {0x00}, {0xba, 0xba, 0xba, 0xba}, {}}

The script `OP_3` (encoded as 0x53) pushes the 1-byte stack element {0x03} onto the stack:

> {{}, {0x00}, {0xba, 0xba, 0xba, 0xba}, {}, {0x03}}

On the other hand, the script `<0x00>` (encoded itself as {0x01, 0x00} pushes the 1-byte value {0x00}:

> {{}, {0x00}, {0xba, 0xba, 0xba, 0xba}, {}, {0x03}, {0x00}}

For the purpose of OP\_CHECKSIG and OP\_CHECKSIGADD, a signature equal to {} is special: this is the only "invalid" signature allowed. Any other signature stack element which doesn't actually verify correctly causes the script execution to abort immediately. An {} signature element simply causes a 0 (= {}) to be pushed onto the stack for OP\_CHECKSIG, and no increment to occur for OP\_CHECKSIGADD.

These rules do *not* apply to the stack element {0x00}, or any other value. The stack element has to be {} exactly. But again, that stack element can appear by being present in the witness stack, where it'd be serialized as {0x00}, or can be pushed using `OP_0` inside script (which is encoded as 0x00 as well).

> **Comments:**
> **username_0**: Wow, what an answer, amazing. Have 2 questions. 1) `An {} signature element simply causes a 0 (= {}) to be pushed onto the stack for OP_CHECKSIG...`, is it more accurate to say ***empty vector*** instead of 0 since 0 can also mean to push literally zero like {0x00}? 2) `But again, that stack element can appear by being present in the witness stack, where it'd be serialized as {0x00}` by this you mean that the witness item is of length 0?  
> **username_0**: Also, 3) If the witness stack have elements with the length of zero (0x00), it won't just ignore them but push empty vector ({}) onto the initial stack. For example, if the witness stack starts like `000000...` it will push three empty vectors ({}) onto the initial stack?  
> **username_1**: (1) They're equivalent; an empty vector is how in the script language the number 0 is represented (as it's also what OP_0 pushed), so they can be used interchangeably. (2) Yes, the serialization of a 0-length stack element is the byte 0x00. (3) Indeed, empty stack elements are very much not ignored. The witness stack serialization {0x00, 0x00, 0x00} indeed represents an initial stack of 3 empty vectors.  
> **username_0**: For the first question. So how can I distinguish 0 in the case of `{}` and `{0x00}`? **Both represent 0.** For example, if someone says there must be a 0 on the stack, does that mean {} or {0x00}? Also, if it says, for example, that the opcode will push a 0 onto the stack or there must be a 0 on the stack for some opcode to pass, is it {} or {0x00} (since both are actually 0). From what I understand looking at what you wrote, it looks like 0 actually just represents the empty vector `{}`, but what is then the *TERM* for pushing 0 as {0x00} onto the stack  (if it exists)?  
> **username_0**: Also, when it says **FALSE** (for example, "*opcode will push FALSE on the stack in order to...*" or "*must be FALSE on stack in order to opcode not invalidate script, otherwise....*"), does in Bitcoin it represent an empty vector (`{}`) on the stack or `{0x00}` on the stack, or both? I assume just the first one (`{}`). **For TRUE** I know that's `{0x01}`.  
> **username_1**: False, 0, and empty vector are all the same thing. I don't think there is a common name for {0x00} as while it's indeed also treated as 0 in numeric context, it's not actually commonly used.  
> **username_0**: Okay, so `{0x00}` on the stack won't be threated as FALSE since FALSE is just an empty vector (`{}`)?  
> **username_1**: Whenever a stack element is treated as a boolean (e.g for OP_BOOLAND), any byte vector that contains a nonzero byte is *treated* as "true", while others are *treated* as "false" (including {}, {0x00}, {0x00, 0x00}, ...) But when we say an opcode "pushes false", it is always {} because the shortest encoding is preferred.  
> **username_0**: That's the answer I was look for, thanks! Just one strange question. How does Bitcoin threat nothing ("air") on the stack. Also as FALSE or will fail the script execution? For example if some opcode require false on the stack, but it finds an empty stack?  
> **username_1**: That's an error. Anything that needs more stack elements than are available causes script execution to abort and treat the transaction as invalid.  
> **username_0**: Just one question related to the **MINIMALIF** rule from the BIP342. It requires either exactly 1 as a top stack element (`{0x01}` as a top stack element) or 0 as a top stack element. Since 0 in Bitcoin, as you previously mentioned, always denotes/represents `{}`, then the `{}` must be the top stack element in this case, and not for example `{0x00}`, `{0x00, 0x00}`. Correct?  
> **username_1**: Indeed, the MINIMALIF rule (consensus in tapscript, a standardness rule for other scripts) requires the input to an OP_IF or OP_NOTIF to be *exactly* {}, or exactly {0x01}.  
> **username_0**: Thanks for all the help!  

---

