Federico Barbacovi
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    1
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- author: - Federico Barbacovi title: "OP_CHECKSIG beyond signature validation: covenants, transaction introspection and PUSHTX" --- # What is this post about? Bitcoin's architecture ensures that only the rightful owner of a satoshi can spend it. The conditions under which a satoshi can be spent are encoded into its locking script, and enforced by miners. It's clear that the most important check is to authenticate the rightful owner of the satoshi, but what if we want to impose other conditions? Locking scripts that put restrictions on how a satoshi can be spent (or, more generally, on how the transaction spending the satoshis can be constructed) are called *covenants*, and are the focus of this post. For quite a while, it wasn't clear whether covenants could be constructed in Bitcoin without changing Bitcoin. However, it has been shown that they are indeed achievable. The key is to use a special opcode: $\texttt{OP_CHECKSIG}$. Even though it was initially designed to verify signatures, it can be leveraged for other uses. In this blogpost and its companion (very soon to follow), we will show how to use $\texttt{OP_CHECKSIG}$ to achieve transaction introspection efficiently. In another (soon to follow) blogpost, we will instead show how $\texttt{OP_CHECKSIG}$ can be used to efficiently verify scalar point multiplications on the Bitcoin curve. Stay tuned for updates! ## A brief history of covenants in Bitcoin Before delving into mathematical and implementation details, we survey the history of covenants in Bitcoin. The idea of covenants first appeared in 2016 in [Enhancing Bitcoin Transactions with Covenants](https://fc17.ifca.ai/bitcoin/papers/bitcoin17-final28.pdf), written by R. O'Connor and M. Piekarska from Blockstream. They explained how to achieve transaction introspection by introducing a new opcode that verifies signatures on arbitrary messages. While the idea is interesting, there was no appetite to introduce a new opcode at the time. Successively (2017), Y. Chan and D. Kramer at nChain came up with the idea of signing messages in Bitcoin Script (which does not require any new opcode), and turned this idea into a recipe to construct covenants. A few years later, sCrypt implemented this idea (you can find a blog post from sCrypt [here](https://scryptplatform.medium.com/op-push-tx-3d3d279174c1)). In 2020, sCrypt came up with a way to [optimise the covenant construction](https://scryptplatform.medium.com/optimal-op-push-tx-ded54990c76f), which leveraged a new insight: the spender can tweak the transaction and put it into a specific form to simplify the signature generation. The optimised construction by sCrypt greatly reduced the script size required to implement a covenant. Up until the blogpost [CAT and Schnorr Tricks I](https://medium.com/blockstream/cat-and-schnorr-tricks-i-faf1b59bd298) by A. Polestra from Blockstream in 2021, all the covenants constructions had been using ECDSA. In his blogpost, Polestra explains how to leverage Schnorr signatures (introduced in BTC with [BIP 340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki)) to construct covenants. Since Polestra's blogpost, the interest in Bitcoin covenants has been renewed ([BIP 347](https://github.com/bitcoin/bips/blob/master/bip-0347.mediawiki), [Implementing a Bridge covenant on $\texttt{OP_CAT}$-enabled Bitcoin](https://starkware.co/blog/implementing-a-bridge-covenant-on-op-cat-bitcoin/)), and here we are today writing about them and their implementation. ## Why is this post so long? Explaining what covenants are is simple, constructing them is harder. We must understand a bit of math, and part of the Bitcoin's node software. That's why the post is long: it contains a blend of math and code. On the flip side, everything is now in one place and can be searched with ease! To maintain a certain flow, we decided to go straight into math and implementation, without presenting all the required definitions. If you are accustomed to elliptic curves and Bitcoin, you can jump right in! If you're not, do not despair. We provide all the necessary details (and links to further resources) [here](https://hackmd.io/@federicobarbacovi/Byz6YfCfyx). Feel free to have a look every time there's a notion you want to brush up on. # <a id="tx-introspection">Transaction introspection</a> For a long time, [locking scripts](#lock-unlock) were used to determine *who* could spend a UTXO but not *how* the UTXO could be spent. In other words, there was an abundance of UTXOs that could only be spent by Alice but none that could only be spent by Alice to pay Bob. The situation has recently changed, and there is now a strong interest in the Bitcoin community for locking scripts that can enforce conditions on the spending of the UTXO, which we call *covenants*. This requires the ability of *transaction introspection*, namely, the locking script must be able to access the transaction in which the UTXO is being spent. The question is, how can this capability be achieved? ## The goal What does it mean that the locking script $\mathsf{lock}$ of $\mathsf{UTXO}$ achieves transaction introspection? It means that at some point during its execution, $\mathsf{lock}$ knows that it is parsing the transaction $\mathsf{tx}$ that spends $\mathsf{UTXO}$, also called the *spending transaction*. As the data on which $\mathsf{lock}$ is executed is passed via the unlocking script $\mathsf{unlock}$, transaction introspection means forcing $\mathsf{unlock}$ to contain $\mathsf{tx}$. Trimming it to the bare minimum, we want to construct $\mathsf{lock}$ such that on input $\mathsf{unlock}= \texttt{<}m' \texttt{>}$ it returns $(m' \overset{?}{=} \mathsf{tx})$, where $\mathsf{tx}$ is the spending transaction.[^1] ## Why so challenging? Why it was not clear that transaction introspection could be achieved is that $\mathsf{lock}$ is executed *only* on the input data $\mathsf{unlock}$. This means that $\mathsf{lock}$ cannot access any information that can be used to validate whether $m'$ is $\mathsf{tx}$ or not. If this last statement were correct, transaction introspection could not be achieved. Fortunately, there is one opcode that can access data outside the one provided by $\mathsf{unlock}$: $\texttt{OP_CHECKSIG}$. At first, it is not clear why $\texttt{OP_CHECKSIG}$ should help us to achieve our goal: this opcode is used to verify signatures, it does not push transaction data to the stack. The point is that $\texttt{OP_CHECKSIG}$ can be used as a source of truth against which we can compare $m'$. ## $\texttt{OP_CHECKSIG}$ How does $\texttt{OP_CHECKSIG}$ work? It takes in a Bitcoin public key and a signature, and verifies the validity of the signature against (a message digest of) the transaction. Let's spell this out in detail. Assume Bob holds a private-public key pair $(sk_B, pk_B)$ for [$\mathsf{secp256k1}$](https://en.bitcoin.it/wiki/Secp256k1). If $$\mathsf{UTXO}.\mathsf{lock}= \texttt{<}pk_B \texttt{>}\; \texttt{OP_CHECKSIG}$$ and[^2] the input of $\mathsf{tx}$ at index $\mathsf{ix}$ is $\mathsf{UTXO}$, i.e., $\mathsf{tx}\mathsf{.in}[\mathsf{ix}] = \mathsf{UTXO}$, then $$\mathsf{ECDSAb}\mathsf{.verify}(sig_B, \mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{b}), pk_B) \leftarrow \texttt{<}sig_B \texttt{>}\; \texttt{<}pk_B \texttt{>}\; \texttt{OP_CHECKSIG}$$ where [$\mathsf{ECDSAb}$](https://hackmd.io/@federicobarbacovi/Byz6YfCfyx#ECDSA) is the version of ECDSA used in Bitcoin, $\mathsf{PreSigHash}$ is the [message digest algorithm](https://hackmd.io/@federicobarbacovi/Byz6YfCfyx#Message-digest-algorithm), and $\mathsf{b}$ is the [SIGHASH flag](https://wiki.bitcoinsv.io/index.php/SIGHASH_flags). Something striking happens here: $\texttt{OP_CHECKSIG}$ returns the validity of $sig_B$ for the message $\mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{b})$ and the public key $pk_B$, but it is not supplied $\mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{b})$ from the script! It means that $\texttt{OP_CHECKSIG}$ is accessing data outside of the unlocking script, and this opens up the possibility of transaction introspection. ## From $\texttt{OP_CHECKSIG}$ to transaction introspection Let's take a step back, and reflect on what conclusions can be drawn from a valid signature $sig_B$ by Bob on message $m$. If $sig_B$ is valid for $pk_B$ on message $m$, it means that Bob signed with his private key $sk_B$, and that he signed $m$. Assume we knew $sk_B$, and that we had access to $\mathsf{ECDSAb}\mathsf{.verify}(-,m,pk_B)$, where $-$ means we consider the first entry a free variable we can supply to the algorithm. Can we come up with a way to validate whether an input $m'$ is equal to $m$? Yes, we can! The algorithm is the following: $$\begin{array}{ll} \textbf{Input:} & m'\\ \textbf{Output:} & (m' \overset{?}{=} m)\\ \textbf{Algorithm:} & \\ \quad \quad 1. \; sig \leftarrow \mathsf{ECDSAb}\mathsf{.sign}(m',sk_B)\\ \quad \quad 2. \; \mathsf{ECDSAb}\mathsf{.verify}\left( sig, m, pk_B \right) \end{array}$$ With high probability, $m' = m$ if and only if the result is $1$ (see [Are we sure covenants are secure?](#security-of-pushtx)). In our setup, we have $m = \mathsf{PreSigHash}(\mathsf{tx}, \mathsf{ix}, \mathsf{ALL})$, but what about $sk_B$? Note that Bob does not play any role in what we have described! What we needed was the ability to verify a signature on a given message with respect to a fixed public key. We are free to choose the public key, so we fix $sk_B = 1$, $pk_B = G$ (the generator of $\mathsf{secp256k1}$). The question now is, can we turn the above algorithm into a locking script $\mathsf{lock}$? If we could, then $\mathsf{lock}$ would achieve transaction introspection. What we need to do in Bitcoin Script is: 1. Compute $\mathsf{ECDSAb}\mathsf{.sign}(m',1)$ starting from $m'$. 2. Access $\mathsf{ECDSAb}\mathsf{.verify}(-,\mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{ALL}),G)$ The great news is that we can perform both step 1 and step 2! We explained that $$\mathsf{ECDSAb}\mathsf{.verify}(-,\mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{ALL}),G) = \texttt{<->} \; \texttt{<}G \texttt{>}\; \texttt{OP_CHECKSIG}$$ and thus step 2 can be turned into Bitcoin Script. [Below](#from-m-to-sig) we explain how to compute $\mathsf{ECDSAb}\mathsf{.sign}(m',1)$ in Script. We have covered all the ideas required to construct a locking script that achieves transaction introspection. Let's dive into the implementation of these ideas! # PUSHTX Let's give a name to the locking script that achieves transaction introspection: we call it PUSHTX, and we write $\texttt{[PUSHTX]}$ for its code implementation. This locking script works as follows: $$(m' \overset{?}{=} \mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{ALL})) \leftarrow \texttt{<$m'$>} \; \texttt{[PUSHTX]}$$ where $\mathsf{tx}\mathsf{.in}[\mathsf{ix}]$ spends the UTXO locked with $\texttt{[PUSHTX]}$, and $m'$ is part of $\mathsf{tx}\mathsf{.in}[\mathsf{ix}]\mathsf{.unlock}$. [We explained](#tx-introspection) how $\texttt{[PUSHTX]}$ can be achieved. We now delve into its implementation. ## <a id="from-m-to-sig">Computing $\mathsf{ECDSAb}\mathsf{.sign}(m',1)$ in Bitcoin Script</a> The first step in implementing $\texttt{[PUSHTX]}$ is computing $\mathsf{ECDSAb}\mathsf{.sign}(m',1)$ given $m'$. If we look at the definition of [$\mathsf{ECDSAb}\mathsf{.sign}$](https://hackmd.io/@federicobarbacovi/Byz6YfCfyx#ECDSA), we see that we should sample a random $k$ from $\mathbb{F}_{n}^{\ast}$, where $n$ is the order of $\mathsf{secp256k1}$. As we do not need to keep $k$ private, we can choose any value for it, and we fix it to be $k = 1$. Then, $$(r,s) \leftarrow \mathsf{ECDSAb}\mathsf{.sign}(m',1)$$ is given by $$r = G_x \quad \quad s = \min \{ \mathsf{HASH256}(m') + G_x, n - (\mathsf{HASH256}(m') + G_x)\} \mod n$$ We can hard-code $r$ in $\texttt{[PUSHTX]}$, while $s$ can be computed on-chain. Unfortunately, its computation is slightly more involved than what it looks like. We would to expect the following script to compute $\mathsf{HASH256}(m') + G_x \mod n$: $$\texttt{<}\mathsf{HASH256}(m') + G_x \mod n \texttt{>}\leftarrow \texttt{<}m \texttt{>}\; \texttt{OP_HASH256}\; \texttt{<}G_x \texttt{>}\; \texttt{OP_ADD}\; \texttt{<}n \texttt{>}\; \texttt{OP_MOD}$$ However, this is not the case, and the problem is something called *endianness*. In a nutshell, when Bitcoin Script interprets an element for the purpose of mathematical operations, it reads it right to left, whereas when it parses it for any other reason (e.g., hashing), it reads it left to right. This means that after hashing $m'$, we need to reverse the order of its bytes. We write a script $\texttt{[REVERSE_ENDIANNESS]}$ that performs this reversal. You can find the full code generating this script [here](https://github.com/nchain-innovation/zkscript_package/blob/0be3b97cc34ec35a60e4172eebf0bc7ac432a17d/src/zkscript/util/utility_scripts.py#L309), we limit ourselves to a pseudocode description: ```python def reverse_endianness(length: int) -> Script: out = "" out += " ".join(["OP_1 OP_SPLIT"] * (length-1)) out += " ".join(["OP_SWAP OP_CAT"] * (length-1)) return out ``` Anyhow, using $\texttt{[REVERSE_ENDIANNESS]}$ and other opcodes, we can construct a script $\texttt{[GENERATE_SIG]}$ that on input $m'$, returns $r$ and $s$: $$\texttt{<}r \texttt{>}\; \texttt{<}s \texttt{>}\leftarrow \texttt{<}m' \texttt{>}\; \texttt{[GENERATE_SIG]}$$ Unfortunately, at this point we stumble onto the same problem once again. Signatures in Bitcoin are serialised according to [DER](https://github.com/bitcoin-sv/bitcoin-sv/blob/86eb5e8bdf5573c3cd844a1d81bd4fb151b909e0/src/script/interpreter.cpp#L164) format, and interpreted reading left to right. Hence, we must reverse the order of the bytes of $r$ and $s$. This further endianness reversal completes the computation of the signature $\mathsf{ECDSAb}\mathsf{.sign}(m',1)$. We write $\texttt{[MESSAGE_TO_SIG]}$ for the script performing this computation: $$\texttt{<}\texttt{DER}(r,s) \texttt{>}\leftarrow \texttt{<}m' \texttt{>}\; \texttt{[MESSAGE_TO_SIG]}$$ ## The final step Now that we have $\texttt{[MESSAGE_TO_SIG]}$ at our disposal, we can complete the implementation of $\texttt{[PUSHTX]}$. The final step is simple: leverage $\texttt{OP_CHECKSIG}$ to verify the validity of the signature we constructed: $$\texttt{[PUSHTX]}:= \texttt{[MESSAGE_TO_SIG]}\; \texttt{<}G_x \texttt{>}\; \texttt{OP_CHECKSIG}$$ and then $$(m' \overset{?}{=} \mathsf{PreSigHash}(\mathsf{tx}, \mathsf{ix}, \mathsf{ALL})) \leftarrow \texttt{<}m' \texttt{>}\; \texttt{[PUSHTX]}$$ You can find the implementation of $\texttt{[PUSHTX]}$ [here](https://github.com/nchain-innovation/zkscript_package/blob/0be3b97cc34ec35a60e4172eebf0bc7ac432a17d/src/zkscript/transaction_introspection/transaction_introspection.py#L39) and the opcodes that make up $\texttt{[PUSHTX]}$ [here](https://test.whatsonchain.com/tx/a626525eb792dc6d2ff51739b9be84288f46b37c6fa49970e44694c9ea0b8fc3?tab=scripts) (see also [On-chain deployment](#On-chain-deployment)). What's the total script size, you asked? $\texttt{[PUSHTX]}$ requires $376$ bytes, the biggest overhead being due to the endianness reversals, which accounts for $228$ bytes. The image below gives a visual breakdown of the code that makes up $\texttt{[PUSHTX]}$ (the image was generated with [Carbon](https://carbon.now.sh/)) ![pushtx_logic](https://hackmd.io/_uploads/SyHMC-8X1e.png) ## Can we do better? As always, when implementing an algorithm in Bitcoin Script we challenge ourselves to do better (in terms of script size) than what we have done. We did it when we implemented [Merkle trees](https://hackmd.io/@federicobarbacovi/BybFoBplJx), and we do it now that we have implemented $\texttt{[PUSHTX]}$. We believe this post is already long enough, so we delegate the answer to the question *can we do better?* to a companion post (soon to follow). Be sure to check it out! Spoiler alert, *we can do better!* # On-chain deployment We deployed $\texttt{[PUSHTX]}$ on-chain. We locked the output of [tx/a626..8fc3](https://test.whatsonchain.com/tx/a626525eb792dc6d2ff51739b9be84288f46b37c6fa49970e44694c9ea0b8fc3) with a locking script that allows spending only if the version number of the spending transaction is $\texttt{0x24201118}$ (the date of the day in which we created and spent the UTXO, written in little endian). We spent this UTXO at [tx/3c4d..0777](https://test.whatsonchain.com/tx/3c4dd601f82d9ed1b3cd6491cfbf3bf07f1b3340545d7bf26dcf9ce5e13c0777). Thanks to the modular structure of [zkscript](https://github.com/nchain-innovation/zkscript_package), constructing the locking script is very easy: ```python from tx_engine import Script, SIGHASH from src.zkscript.transaction_introspection.transaction_introspection import ( TransactionIntrospection ) locking_script_fixed_tx_version = TransactionIntrospection.pushtx( sighash_value=SIGHASH.ALL_FORKID, rolling_option=False ) locking_script_fixed_tx_version += Script.parse_string( "OP_4 OP_SPLIT OP_DROP" ) # Get tx.version locking_script_fixed_tx_version.append_pushdata( bytes.fromhex("18112024") ) locking_script_fixed_tx_version += Script.parse_string( "OP_EQUAL" ) # Enforce tx.version = 0x18112024 ``` # <a id="security-of-pushtx">Are we sure covenants are secure?</a> The reason why $\texttt{[PUSHTX]}$ is secure is at it leverages $\mathsf{ECDSAb}$, which is known to be secure under the assumption that $\mathsf{HASH256}$ is a [one way](https://en.wikipedia.org/wiki/One-way_function), [collision resistant hash function](https://en.wikipedia.org/wiki/Cryptographic_hash_function) (and that discrete logarithms are hard in $\mathsf{secp256k1}$). As $k = sk = 1$ are fixed in $\texttt{[PUSHTX]}$, the only way an attacker can trick $\texttt{[PUSHTX]}$ is by finding $m'$ such that $m' \neq \mathsf{PreSigHash}(\mathsf{tx}, \mathsf{ix}, \mathsf{ALL})$ and $$\mathsf{ECDSAb}\mathsf{.sign}(m',1) = \mathsf{ECDSAb}\mathsf{.sign}(\mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{ALL}),1) \mod n$$ By the definition of the signature algorithm, this means that the attacker has found $m' \neq \mathsf{PreSigHash}(\mathsf{tx}, \mathsf{ix}, \mathsf{ALL})$ such that $$\mathsf{HASH256}(m') = \pm \mathsf{HASH256}(\mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{ALL})) \mod n$$ If such an attacker $\mathcal{A}$ existed, we could break collision resistance of $\mathsf{HASH256}$ as follows: - Select a random transaction $\mathsf{tx}$ and a random index $\mathsf{ix}\leq n_{in} - 1$ - Run the attacker 5 times on input $\mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{ALL})$ and denote $m_i'$ the output of the $i$-th execution - If: 1. For one the attempts we have $$\mathsf{HASH256}(m') = \mathsf{HASH256}(\mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{ALL}))$$ return $m', \mathsf{PreSigHash}(\mathsf{tx},\mathsf{ix},\mathsf{ALL})$ 2. If there are two attempts such that $\mathsf{HASH256}(m_i') = \mathsf{HASH256}(m_j')$ with $i \neq j$, return $m_i', m_j'$ Write $\mathcal{A}'$ for the algorithm described above. Then $\mathcal{A}'$ succeeds in breaking collision resistance of $\mathsf{HASH256}$ with probability bigger or equal than the probability that $\mathcal{A}$ succeeds five times in a row (up to a negligible difference). Indeed, if $\mathcal{A}$ succeeds five times in a row, then either case 1 happens, or case 2 happens by the [pigeonhole principle](https://en.wikipedia.org/wiki/Pigeonhole_principle). In both cases, we break collision resistance.[^3] [^1]: In reality, we will check that $m'$ is equal to the message digest of $\mathsf{tx}$. Keep reading to know more! [^2]: For the notation we use to denote the elements of a Bitcoin transactions, see [here](https://hackmd.io/@federicobarbacovi/Byz6YfCfyx#Transactions). [^3]: The probability of success of $\mathcal{A}'$ is slightly less than the probability of $\mathcal{A}$ succeeding five times in a row because it could happen that $m_i' = m_j'$, but as $\mathsf{HASH256}$ compresses its inputs, this probability is very low, see [this](https://www.cs.ucdavis.edu/~rogaway/papers/relates.pdf) paper by Rogaway and Shrimpton.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully